[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / flang / lib / Optimizer / Dialect / FIROps.cpp
blobcdcf9bda49a627af7b9b5e8c55cca6c6afc249bf
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
11 //===----------------------------------------------------------------------===//
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 "llvm/ADT/STLExtras.h"
33 #include "llvm/ADT/SmallVector.h"
34 #include "llvm/ADT/TypeSwitch.h"
36 namespace {
37 #include "flang/Optimizer/Dialect/CanonicalizationPatterns.inc"
38 } // namespace
40 static void propagateAttributes(mlir::Operation *fromOp,
41 mlir::Operation *toOp) {
42 if (!fromOp || !toOp)
43 return;
45 for (mlir::NamedAttribute attr : fromOp->getAttrs()) {
46 if (attr.getName().getValue().starts_with(
47 mlir::acc::OpenACCDialect::getDialectNamespace()))
48 toOp->setAttr(attr.getName(), attr.getValue());
52 /// Return true if a sequence type is of some incomplete size or a record type
53 /// is malformed or contains an incomplete sequence type. An incomplete sequence
54 /// type is one with more unknown extents in the type than have been provided
55 /// via `dynamicExtents`. Sequence types with an unknown rank are incomplete by
56 /// definition.
57 static bool verifyInType(mlir::Type inType,
58 llvm::SmallVectorImpl<llvm::StringRef> &visited,
59 unsigned dynamicExtents = 0) {
60 if (auto st = mlir::dyn_cast<fir::SequenceType>(inType)) {
61 auto shape = st.getShape();
62 if (shape.size() == 0)
63 return true;
64 for (std::size_t i = 0, end = shape.size(); i < end; ++i) {
65 if (shape[i] != fir::SequenceType::getUnknownExtent())
66 continue;
67 if (dynamicExtents-- == 0)
68 return true;
70 } else if (auto rt = mlir::dyn_cast<fir::RecordType>(inType)) {
71 // don't recurse if we're already visiting this one
72 if (llvm::is_contained(visited, rt.getName()))
73 return false;
74 // keep track of record types currently being visited
75 visited.push_back(rt.getName());
76 for (auto &field : rt.getTypeList())
77 if (verifyInType(field.second, visited))
78 return true;
79 visited.pop_back();
81 return false;
84 static bool verifyTypeParamCount(mlir::Type inType, unsigned numParams) {
85 auto ty = fir::unwrapSequenceType(inType);
86 if (numParams > 0) {
87 if (auto recTy = mlir::dyn_cast<fir::RecordType>(ty))
88 return numParams != recTy.getNumLenParams();
89 if (auto chrTy = mlir::dyn_cast<fir::CharacterType>(ty))
90 return !(numParams == 1 && chrTy.hasDynamicLen());
91 return true;
93 if (auto chrTy = mlir::dyn_cast<fir::CharacterType>(ty))
94 return !chrTy.hasConstantLen();
95 return false;
98 /// Parser shared by Alloca and Allocmem
99 ///
100 /// operation ::= %res = (`fir.alloca` | `fir.allocmem`) $in_type
101 /// ( `(` $typeparams `)` )? ( `,` $shape )?
102 /// attr-dict-without-keyword
103 template <typename FN>
104 static mlir::ParseResult parseAllocatableOp(FN wrapResultType,
105 mlir::OpAsmParser &parser,
106 mlir::OperationState &result) {
107 mlir::Type intype;
108 if (parser.parseType(intype))
109 return mlir::failure();
110 auto &builder = parser.getBuilder();
111 result.addAttribute("in_type", mlir::TypeAttr::get(intype));
112 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
113 llvm::SmallVector<mlir::Type> typeVec;
114 bool hasOperands = false;
115 std::int32_t typeparamsSize = 0;
116 if (!parser.parseOptionalLParen()) {
117 // parse the LEN params of the derived type. (<params> : <types>)
118 if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None) ||
119 parser.parseColonTypeList(typeVec) || parser.parseRParen())
120 return mlir::failure();
121 typeparamsSize = operands.size();
122 hasOperands = true;
124 std::int32_t shapeSize = 0;
125 if (!parser.parseOptionalComma()) {
126 // parse size to scale by, vector of n dimensions of type index
127 if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None))
128 return mlir::failure();
129 shapeSize = operands.size() - typeparamsSize;
130 auto idxTy = builder.getIndexType();
131 for (std::int32_t i = typeparamsSize, end = operands.size(); i != end; ++i)
132 typeVec.push_back(idxTy);
133 hasOperands = true;
135 if (hasOperands &&
136 parser.resolveOperands(operands, typeVec, parser.getNameLoc(),
137 result.operands))
138 return mlir::failure();
139 mlir::Type restype = wrapResultType(intype);
140 if (!restype) {
141 parser.emitError(parser.getNameLoc(), "invalid allocate type: ") << intype;
142 return mlir::failure();
144 result.addAttribute("operandSegmentSizes", builder.getDenseI32ArrayAttr(
145 {typeparamsSize, shapeSize}));
146 if (parser.parseOptionalAttrDict(result.attributes) ||
147 parser.addTypeToList(restype, result.types))
148 return mlir::failure();
149 return mlir::success();
152 template <typename OP>
153 static void printAllocatableOp(mlir::OpAsmPrinter &p, OP &op) {
154 p << ' ' << op.getInType();
155 if (!op.getTypeparams().empty()) {
156 p << '(' << op.getTypeparams() << " : " << op.getTypeparams().getTypes()
157 << ')';
159 // print the shape of the allocation (if any); all must be index type
160 for (auto sh : op.getShape()) {
161 p << ", ";
162 p.printOperand(sh);
164 p.printOptionalAttrDict(op->getAttrs(), {"in_type", "operandSegmentSizes"});
167 //===----------------------------------------------------------------------===//
168 // AllocaOp
169 //===----------------------------------------------------------------------===//
171 /// Create a legal memory reference as return type
172 static mlir::Type wrapAllocaResultType(mlir::Type intype) {
173 // FIR semantics: memory references to memory references are disallowed
174 if (mlir::isa<fir::ReferenceType>(intype))
175 return {};
176 return fir::ReferenceType::get(intype);
179 mlir::Type fir::AllocaOp::getAllocatedType() {
180 return mlir::cast<fir::ReferenceType>(getType()).getEleTy();
183 mlir::Type fir::AllocaOp::getRefTy(mlir::Type ty) {
184 return fir::ReferenceType::get(ty);
187 void fir::AllocaOp::build(mlir::OpBuilder &builder,
188 mlir::OperationState &result, mlir::Type inType,
189 llvm::StringRef uniqName, mlir::ValueRange typeparams,
190 mlir::ValueRange shape,
191 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
192 auto nameAttr = builder.getStringAttr(uniqName);
193 build(builder, result, wrapAllocaResultType(inType), inType, nameAttr, {},
194 /*pinned=*/false, typeparams, shape);
195 result.addAttributes(attributes);
198 void fir::AllocaOp::build(mlir::OpBuilder &builder,
199 mlir::OperationState &result, mlir::Type inType,
200 llvm::StringRef uniqName, bool pinned,
201 mlir::ValueRange typeparams, mlir::ValueRange shape,
202 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
203 auto nameAttr = builder.getStringAttr(uniqName);
204 build(builder, result, wrapAllocaResultType(inType), inType, nameAttr, {},
205 pinned, typeparams, shape);
206 result.addAttributes(attributes);
209 void fir::AllocaOp::build(mlir::OpBuilder &builder,
210 mlir::OperationState &result, mlir::Type inType,
211 llvm::StringRef uniqName, llvm::StringRef bindcName,
212 mlir::ValueRange typeparams, mlir::ValueRange shape,
213 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
214 auto nameAttr =
215 uniqName.empty() ? mlir::StringAttr{} : builder.getStringAttr(uniqName);
216 auto bindcAttr =
217 bindcName.empty() ? mlir::StringAttr{} : builder.getStringAttr(bindcName);
218 build(builder, result, wrapAllocaResultType(inType), inType, nameAttr,
219 bindcAttr, /*pinned=*/false, typeparams, shape);
220 result.addAttributes(attributes);
223 void fir::AllocaOp::build(mlir::OpBuilder &builder,
224 mlir::OperationState &result, mlir::Type inType,
225 llvm::StringRef uniqName, llvm::StringRef bindcName,
226 bool pinned, mlir::ValueRange typeparams,
227 mlir::ValueRange shape,
228 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
229 auto nameAttr =
230 uniqName.empty() ? mlir::StringAttr{} : builder.getStringAttr(uniqName);
231 auto bindcAttr =
232 bindcName.empty() ? mlir::StringAttr{} : builder.getStringAttr(bindcName);
233 build(builder, result, wrapAllocaResultType(inType), inType, nameAttr,
234 bindcAttr, pinned, typeparams, shape);
235 result.addAttributes(attributes);
238 void fir::AllocaOp::build(mlir::OpBuilder &builder,
239 mlir::OperationState &result, mlir::Type inType,
240 mlir::ValueRange typeparams, mlir::ValueRange shape,
241 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
242 build(builder, result, wrapAllocaResultType(inType), inType, {}, {},
243 /*pinned=*/false, typeparams, shape);
244 result.addAttributes(attributes);
247 void fir::AllocaOp::build(mlir::OpBuilder &builder,
248 mlir::OperationState &result, mlir::Type inType,
249 bool pinned, mlir::ValueRange typeparams,
250 mlir::ValueRange shape,
251 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
252 build(builder, result, wrapAllocaResultType(inType), inType, {}, {}, pinned,
253 typeparams, shape);
254 result.addAttributes(attributes);
257 mlir::ParseResult fir::AllocaOp::parse(mlir::OpAsmParser &parser,
258 mlir::OperationState &result) {
259 return parseAllocatableOp(wrapAllocaResultType, parser, result);
262 void fir::AllocaOp::print(mlir::OpAsmPrinter &p) {
263 printAllocatableOp(p, *this);
266 llvm::LogicalResult fir::AllocaOp::verify() {
267 llvm::SmallVector<llvm::StringRef> visited;
268 if (verifyInType(getInType(), visited, numShapeOperands()))
269 return emitOpError("invalid type for allocation");
270 if (verifyTypeParamCount(getInType(), numLenParams()))
271 return emitOpError("LEN params do not correspond to type");
272 mlir::Type outType = getType();
273 if (!mlir::isa<fir::ReferenceType>(outType))
274 return emitOpError("must be a !fir.ref type");
275 return mlir::success();
278 bool fir::AllocaOp::ownsNestedAlloca(mlir::Operation *op) {
279 return op->hasTrait<mlir::OpTrait::IsIsolatedFromAbove>() ||
280 op->hasTrait<mlir::OpTrait::AutomaticAllocationScope>() ||
281 mlir::isa<mlir::LoopLikeOpInterface>(*op);
284 mlir::Region *fir::AllocaOp::getOwnerRegion() {
285 mlir::Operation *currentOp = getOperation();
286 while (mlir::Operation *parentOp = currentOp->getParentOp()) {
287 // If the operation was not registered, inquiries about its traits will be
288 // incorrect and it is not possible to reason about the operation. This
289 // should not happen in a normal Fortran compilation flow, but be foolproof.
290 if (!parentOp->isRegistered())
291 return nullptr;
292 if (fir::AllocaOp::ownsNestedAlloca(parentOp))
293 return currentOp->getParentRegion();
294 currentOp = parentOp;
296 return nullptr;
299 //===----------------------------------------------------------------------===//
300 // AllocMemOp
301 //===----------------------------------------------------------------------===//
303 /// Create a legal heap reference as return type
304 static mlir::Type wrapAllocMemResultType(mlir::Type intype) {
305 // Fortran semantics: C852 an entity cannot be both ALLOCATABLE and POINTER
306 // 8.5.3 note 1 prohibits ALLOCATABLE procedures as well
307 // FIR semantics: one may not allocate a memory reference value
308 if (mlir::isa<fir::ReferenceType, fir::HeapType, fir::PointerType,
309 mlir::FunctionType>(intype))
310 return {};
311 return fir::HeapType::get(intype);
314 mlir::Type fir::AllocMemOp::getAllocatedType() {
315 return mlir::cast<fir::HeapType>(getType()).getEleTy();
318 mlir::Type fir::AllocMemOp::getRefTy(mlir::Type ty) {
319 return fir::HeapType::get(ty);
322 void fir::AllocMemOp::build(mlir::OpBuilder &builder,
323 mlir::OperationState &result, mlir::Type inType,
324 llvm::StringRef uniqName,
325 mlir::ValueRange typeparams, mlir::ValueRange shape,
326 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
327 auto nameAttr = builder.getStringAttr(uniqName);
328 build(builder, result, wrapAllocMemResultType(inType), inType, nameAttr, {},
329 typeparams, shape);
330 result.addAttributes(attributes);
333 void fir::AllocMemOp::build(mlir::OpBuilder &builder,
334 mlir::OperationState &result, mlir::Type inType,
335 llvm::StringRef uniqName, llvm::StringRef bindcName,
336 mlir::ValueRange typeparams, mlir::ValueRange shape,
337 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
338 auto nameAttr = builder.getStringAttr(uniqName);
339 auto bindcAttr = builder.getStringAttr(bindcName);
340 build(builder, result, wrapAllocMemResultType(inType), inType, nameAttr,
341 bindcAttr, typeparams, shape);
342 result.addAttributes(attributes);
345 void fir::AllocMemOp::build(mlir::OpBuilder &builder,
346 mlir::OperationState &result, mlir::Type inType,
347 mlir::ValueRange typeparams, mlir::ValueRange shape,
348 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
349 build(builder, result, wrapAllocMemResultType(inType), inType, {}, {},
350 typeparams, shape);
351 result.addAttributes(attributes);
354 mlir::ParseResult fir::AllocMemOp::parse(mlir::OpAsmParser &parser,
355 mlir::OperationState &result) {
356 return parseAllocatableOp(wrapAllocMemResultType, parser, result);
359 void fir::AllocMemOp::print(mlir::OpAsmPrinter &p) {
360 printAllocatableOp(p, *this);
363 llvm::LogicalResult fir::AllocMemOp::verify() {
364 llvm::SmallVector<llvm::StringRef> visited;
365 if (verifyInType(getInType(), visited, numShapeOperands()))
366 return emitOpError("invalid type for allocation");
367 if (verifyTypeParamCount(getInType(), numLenParams()))
368 return emitOpError("LEN params do not correspond to type");
369 mlir::Type outType = getType();
370 if (!mlir::dyn_cast<fir::HeapType>(outType))
371 return emitOpError("must be a !fir.heap type");
372 if (fir::isa_unknown_size_box(fir::dyn_cast_ptrEleTy(outType)))
373 return emitOpError("cannot allocate !fir.box of unknown rank or type");
374 return mlir::success();
377 //===----------------------------------------------------------------------===//
378 // ArrayCoorOp
379 //===----------------------------------------------------------------------===//
381 // CHARACTERs and derived types with LEN PARAMETERs are dependent types that
382 // require runtime values to fully define the type of an object.
383 static bool validTypeParams(mlir::Type dynTy, mlir::ValueRange typeParams) {
384 dynTy = fir::unwrapAllRefAndSeqType(dynTy);
385 // A box value will contain type parameter values itself.
386 if (mlir::isa<fir::BoxType>(dynTy))
387 return typeParams.size() == 0;
388 // Derived type must have all type parameters satisfied.
389 if (auto recTy = mlir::dyn_cast<fir::RecordType>(dynTy))
390 return typeParams.size() == recTy.getNumLenParams();
391 // Characters with non-constant LEN must have a type parameter value.
392 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(dynTy))
393 if (charTy.hasDynamicLen())
394 return typeParams.size() == 1;
395 // Otherwise, any type parameters are invalid.
396 return typeParams.size() == 0;
399 llvm::LogicalResult fir::ArrayCoorOp::verify() {
400 auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
401 auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);
402 if (!arrTy)
403 return emitOpError("must be a reference to an array");
404 auto arrDim = arrTy.getDimension();
406 if (auto shapeOp = getShape()) {
407 auto shapeTy = shapeOp.getType();
408 unsigned shapeTyRank = 0;
409 if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy)) {
410 shapeTyRank = s.getRank();
411 } else if (auto ss = mlir::dyn_cast<fir::ShapeShiftType>(shapeTy)) {
412 shapeTyRank = ss.getRank();
413 } else {
414 auto s = mlir::cast<fir::ShiftType>(shapeTy);
415 shapeTyRank = s.getRank();
416 // TODO: it looks like PreCGRewrite and CodeGen can support
417 // fir.shift with plain array reference, so we may consider
418 // removing this check.
419 if (!mlir::isa<fir::BaseBoxType>(getMemref().getType()))
420 return emitOpError("shift can only be provided with fir.box memref");
422 if (arrDim && arrDim != shapeTyRank)
423 return emitOpError("rank of dimension mismatched");
424 // TODO: support slicing with changing the number of dimensions,
425 // e.g. when array_coor represents an element access to array(:,1,:)
426 // slice: the shape is 3D and the number of indices is 2 in this case.
427 if (shapeTyRank != getIndices().size())
428 return emitOpError("number of indices do not match dim rank");
431 if (auto sliceOp = getSlice()) {
432 if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))
433 if (!sl.getSubstr().empty())
434 return emitOpError("array_coor cannot take a slice with substring");
435 if (auto sliceTy = mlir::dyn_cast<fir::SliceType>(sliceOp.getType()))
436 if (sliceTy.getRank() != arrDim)
437 return emitOpError("rank of dimension in slice mismatched");
439 if (!validTypeParams(getMemref().getType(), getTypeparams()))
440 return emitOpError("invalid type parameters");
442 return mlir::success();
445 // Pull in fir.embox and fir.rebox into fir.array_coor when possible.
446 struct SimplifyArrayCoorOp : public mlir::OpRewritePattern<fir::ArrayCoorOp> {
447 using mlir::OpRewritePattern<fir::ArrayCoorOp>::OpRewritePattern;
448 llvm::LogicalResult
449 matchAndRewrite(fir::ArrayCoorOp op,
450 mlir::PatternRewriter &rewriter) const override {
451 mlir::Value memref = op.getMemref();
452 if (!mlir::isa<fir::BaseBoxType>(memref.getType()))
453 return mlir::failure();
455 mlir::Value boxedMemref, boxedShape, boxedSlice;
456 if (auto emboxOp =
457 mlir::dyn_cast_or_null<fir::EmboxOp>(memref.getDefiningOp())) {
458 boxedMemref = emboxOp.getMemref();
459 boxedShape = emboxOp.getShape();
460 boxedSlice = emboxOp.getSlice();
461 // If any of operands, that are not currently supported for migration
462 // to ArrayCoorOp, is present, don't rewrite.
463 if (!emboxOp.getTypeparams().empty() || emboxOp.getSourceBox() ||
464 emboxOp.getAccessMap())
465 return mlir::failure();
466 } else if (auto reboxOp = mlir::dyn_cast_or_null<fir::ReboxOp>(
467 memref.getDefiningOp())) {
468 boxedMemref = reboxOp.getBox();
469 boxedShape = reboxOp.getShape();
470 // Avoid pulling in rebox that performs reshaping.
471 // There is no way to represent box reshaping with array_coor.
472 if (boxedShape && !mlir::isa<fir::ShiftType>(boxedShape.getType()))
473 return mlir::failure();
474 boxedSlice = reboxOp.getSlice();
475 } else {
476 return mlir::failure();
479 bool boxedShapeIsShift =
480 boxedShape && mlir::isa<fir::ShiftType>(boxedShape.getType());
481 bool boxedShapeIsShape =
482 boxedShape && mlir::isa<fir::ShapeType>(boxedShape.getType());
483 bool boxedShapeIsShapeShift =
484 boxedShape && mlir::isa<fir::ShapeShiftType>(boxedShape.getType());
486 // Slices changing the number of dimensions are not supported
487 // for array_coor yet.
488 unsigned origBoxRank;
489 if (mlir::isa<fir::BaseBoxType>(boxedMemref.getType()))
490 origBoxRank = fir::getBoxRank(boxedMemref.getType());
491 else if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(
492 fir::unwrapRefType(boxedMemref.getType())))
493 origBoxRank = arrTy.getDimension();
494 else
495 return mlir::failure();
497 if (fir::getBoxRank(memref.getType()) != origBoxRank)
498 return mlir::failure();
500 // Slices with substring are not supported by array_coor.
501 if (boxedSlice)
502 if (auto sliceOp =
503 mlir::dyn_cast_or_null<fir::SliceOp>(boxedSlice.getDefiningOp()))
504 if (!sliceOp.getSubstr().empty())
505 return mlir::failure();
507 // If embox/rebox and array_coor have conflicting shapes or slices,
508 // do nothing.
509 if (op.getShape() && boxedShape && boxedShape != op.getShape())
510 return mlir::failure();
511 if (op.getSlice() && boxedSlice && boxedSlice != op.getSlice())
512 return mlir::failure();
514 std::optional<IndicesVectorTy> shiftedIndices;
515 // The embox/rebox and array_coor either have compatible
516 // shape/slice at this point or shape/slice is null
517 // in one of them but not in the other.
518 // The compatibility means they are equal or both null.
519 if (!op.getShape()) {
520 if (boxedShape) {
521 if (op.getSlice()) {
522 if (!boxedSlice) {
523 if (boxedShapeIsShift) {
524 // %0 = fir.rebox %arg(%shift)
525 // %1 = fir.array_coor %0 [%slice] %idx
526 // Both the slice indices and %idx are 1-based, so the rebox
527 // may be pulled in as:
528 // %1 = fir.array_coor %arg [%slice] %idx
529 boxedShape = nullptr;
530 } else if (boxedShapeIsShape) {
531 // %0 = fir.embox %arg(%shape)
532 // %1 = fir.array_coor %0 [%slice] %idx
533 // Pull in as:
534 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
535 } else if (boxedShapeIsShapeShift) {
536 // %0 = fir.embox %arg(%shapeshift)
537 // %1 = fir.array_coor %0 [%slice] %idx
538 // Pull in as:
539 // %shape = fir.shape <extents from the %shapeshift>
540 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
541 boxedShape = getShapeFromShapeShift(boxedShape, rewriter);
542 if (!boxedShape)
543 return mlir::failure();
544 } else {
545 return mlir::failure();
547 } else {
548 if (boxedShapeIsShift) {
549 // %0 = fir.rebox %arg(%shift) [%slice]
550 // %1 = fir.array_coor %0 [%slice] %idx
551 // This FIR may only be valid if the shape specifies
552 // that all lower bounds are 1s and the slice's start indices
553 // and strides are all 1s.
554 // We could pull in the rebox as:
555 // %1 = fir.array_coor %arg [%slice] %idx
556 // Do not do anything for the time being.
557 return mlir::failure();
558 } else if (boxedShapeIsShape) {
559 // %0 = fir.embox %arg(%shape) [%slice]
560 // %1 = fir.array_coor %0 [%slice] %idx
561 // This FIR may only be valid if the slice's start indices
562 // and strides are all 1s.
563 // We could pull in the embox as:
564 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
565 return mlir::failure();
566 } else if (boxedShapeIsShapeShift) {
567 // %0 = fir.embox %arg(%shapeshift) [%slice]
568 // %1 = fir.array_coor %0 [%slice] %idx
569 // This FIR may only be valid if the shape specifies
570 // that all lower bounds are 1s and the slice's start indices
571 // and strides are all 1s.
572 // We could pull in the embox as:
573 // %shape = fir.shape <extents from the %shapeshift>
574 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
575 return mlir::failure();
576 } else {
577 return mlir::failure();
580 } else { // !op.getSlice()
581 if (!boxedSlice) {
582 if (boxedShapeIsShift) {
583 // %0 = fir.rebox %arg(%shift)
584 // %1 = fir.array_coor %0 %idx
585 // Pull in as:
586 // %1 = fir.array_coor %arg %idx
587 boxedShape = nullptr;
588 } else if (boxedShapeIsShape) {
589 // %0 = fir.embox %arg(%shape)
590 // %1 = fir.array_coor %0 %idx
591 // Pull in as:
592 // %1 = fir.array_coor %arg(%shape) %idx
593 } else if (boxedShapeIsShapeShift) {
594 // %0 = fir.embox %arg(%shapeshift)
595 // %1 = fir.array_coor %0 %idx
596 // Pull in as:
597 // %shape = fir.shape <extents from the %shapeshift>
598 // %1 = fir.array_coor %arg(%shape) %idx
599 boxedShape = getShapeFromShapeShift(boxedShape, rewriter);
600 if (!boxedShape)
601 return mlir::failure();
602 } else {
603 return mlir::failure();
605 } else {
606 if (boxedShapeIsShift) {
607 // %0 = fir.embox %arg(%shift) [%slice]
608 // %1 = fir.array_coor %0 %idx
609 // Pull in as:
610 // %tmp = arith.addi %idx, %shift.origin
611 // %idx_shifted = arith.subi %tmp, 1
612 // %1 = fir.array_coor %arg(%shift) %[slice] %idx_shifted
613 shiftedIndices =
614 getShiftedIndices(boxedShape, op.getIndices(), rewriter);
615 if (!shiftedIndices)
616 return mlir::failure();
617 } else if (boxedShapeIsShape) {
618 // %0 = fir.embox %arg(%shape) [%slice]
619 // %1 = fir.array_coor %0 %idx
620 // Pull in as:
621 // %1 = fir.array_coor %arg(%shape) %[slice] %idx
622 } else if (boxedShapeIsShapeShift) {
623 // %0 = fir.embox %arg(%shapeshift) [%slice]
624 // %1 = fir.array_coor %0 %idx
625 // Pull in as:
626 // %tmp = arith.addi %idx, %shapeshift.lb
627 // %idx_shifted = arith.subi %tmp, 1
628 // %1 = fir.array_coor %arg(%shapeshift) %[slice] %idx_shifted
629 shiftedIndices =
630 getShiftedIndices(boxedShape, op.getIndices(), rewriter);
631 if (!shiftedIndices)
632 return mlir::failure();
633 } else {
634 return mlir::failure();
638 } else { // !boxedShape
639 if (op.getSlice()) {
640 if (!boxedSlice) {
641 // %0 = fir.rebox %arg
642 // %1 = fir.array_coor %0 [%slice] %idx
643 // Pull in as:
644 // %1 = fir.array_coor %arg [%slice] %idx
645 } else {
646 // %0 = fir.rebox %arg [%slice]
647 // %1 = fir.array_coor %0 [%slice] %idx
648 // This is a valid FIR iff the slice's lower bounds
649 // and strides are all 1s.
650 // Pull in as:
651 // %1 = fir.array_coor %arg [%slice] %idx
653 } else { // !op.getSlice()
654 if (!boxedSlice) {
655 // %0 = fir.rebox %arg
656 // %1 = fir.array_coor %0 %idx
657 // Pull in as:
658 // %1 = fir.array_coor %arg %idx
659 } else {
660 // %0 = fir.rebox %arg [%slice]
661 // %1 = fir.array_coor %0 %idx
662 // Pull in as:
663 // %1 = fir.array_coor %arg [%slice] %idx
667 } else { // op.getShape()
668 if (boxedShape) {
669 // Check if pulling in non-default shape is correct.
670 if (op.getSlice()) {
671 if (!boxedSlice) {
672 // %0 = fir.embox %arg(%shape)
673 // %1 = fir.array_coor %0(%shape) [%slice] %idx
674 // Pull in as:
675 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
676 } else {
677 // %0 = fir.embox %arg(%shape) [%slice]
678 // %1 = fir.array_coor %0(%shape) [%slice] %idx
679 // Pull in as:
680 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
682 } else { // !op.getSlice()
683 if (!boxedSlice) {
684 // %0 = fir.embox %arg(%shape)
685 // %1 = fir.array_coor %0(%shape) %idx
686 // Pull in as:
687 // %1 = fir.array_coor %arg(%shape) %idx
688 } else {
689 // %0 = fir.embox %arg(%shape) [%slice]
690 // %1 = fir.array_coor %0(%shape) %idx
691 // Pull in as:
692 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
695 } else { // !boxedShape
696 if (op.getSlice()) {
697 if (!boxedSlice) {
698 // %0 = fir.rebox %arg
699 // %1 = fir.array_coor %0(%shape) [%slice] %idx
700 // Pull in as:
701 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
702 } else {
703 // %0 = fir.rebox %arg [%slice]
704 // %1 = fir.array_coor %0(%shape) [%slice] %idx
705 return mlir::failure();
707 } else { // !op.getSlice()
708 if (!boxedSlice) {
709 // %0 = fir.rebox %arg
710 // %1 = fir.array_coor %0(%shape) %idx
711 // Pull in as:
712 // %1 = fir.array_coor %arg(%shape) %idx
713 } else {
714 // %0 = fir.rebox %arg [%slice]
715 // %1 = fir.array_coor %0(%shape) %idx
716 // Cannot pull in without adjusting the slice indices.
717 return mlir::failure();
723 // TODO: temporarily avoid producing array_coor with the shape shift
724 // and plain array reference (it seems to be a limitation of
725 // ArrayCoorOp verifier).
726 if (!mlir::isa<fir::BaseBoxType>(boxedMemref.getType())) {
727 if (boxedShape) {
728 if (mlir::isa<fir::ShiftType>(boxedShape.getType()))
729 return mlir::failure();
730 } else if (op.getShape() &&
731 mlir::isa<fir::ShiftType>(op.getShape().getType())) {
732 return mlir::failure();
736 rewriter.modifyOpInPlace(op, [&]() {
737 op.getMemrefMutable().assign(boxedMemref);
738 if (boxedShape)
739 op.getShapeMutable().assign(boxedShape);
740 if (boxedSlice)
741 op.getSliceMutable().assign(boxedSlice);
742 if (shiftedIndices)
743 op.getIndicesMutable().assign(*shiftedIndices);
745 return mlir::success();
748 private:
749 using IndicesVectorTy = std::vector<mlir::Value>;
751 // If v is a shape_shift operation:
752 // fir.shape_shift %l1, %e1, %l2, %e2, ...
753 // create:
754 // fir.shape %e1, %e2, ...
755 static mlir::Value getShapeFromShapeShift(mlir::Value v,
756 mlir::PatternRewriter &rewriter) {
757 auto shapeShiftOp =
758 mlir::dyn_cast_or_null<fir::ShapeShiftOp>(v.getDefiningOp());
759 if (!shapeShiftOp)
760 return nullptr;
761 mlir::OpBuilder::InsertionGuard guard(rewriter);
762 rewriter.setInsertionPoint(shapeShiftOp);
763 return rewriter.create<fir::ShapeOp>(shapeShiftOp.getLoc(),
764 shapeShiftOp.getExtents());
767 static std::optional<IndicesVectorTy>
768 getShiftedIndices(mlir::Value v, mlir::ValueRange indices,
769 mlir::PatternRewriter &rewriter) {
770 auto insertAdjustments = [&](mlir::Operation *op, mlir::ValueRange lbs) {
771 // Compute the shifted indices using the extended type.
772 // Note that this can probably result in less efficient
773 // MLIR and further LLVM IR due to the extra conversions.
774 mlir::OpBuilder::InsertPoint savedIP = rewriter.saveInsertionPoint();
775 rewriter.setInsertionPoint(op);
776 mlir::Location loc = op->getLoc();
777 mlir::Type idxTy = rewriter.getIndexType();
778 mlir::Value one = rewriter.create<mlir::arith::ConstantOp>(
779 loc, idxTy, rewriter.getIndexAttr(1));
780 rewriter.restoreInsertionPoint(savedIP);
781 auto nsw = mlir::arith::IntegerOverflowFlags::nsw;
783 IndicesVectorTy shiftedIndices;
784 for (auto [lb, idx] : llvm::zip(lbs, indices)) {
785 mlir::Value extLb = rewriter.create<fir::ConvertOp>(loc, idxTy, lb);
786 mlir::Value extIdx = rewriter.create<fir::ConvertOp>(loc, idxTy, idx);
787 mlir::Value add =
788 rewriter.create<mlir::arith::AddIOp>(loc, extIdx, extLb, nsw);
789 mlir::Value sub =
790 rewriter.create<mlir::arith::SubIOp>(loc, add, one, nsw);
791 shiftedIndices.push_back(sub);
794 return shiftedIndices;
797 if (auto shiftOp =
798 mlir::dyn_cast_or_null<fir::ShiftOp>(v.getDefiningOp())) {
799 return insertAdjustments(shiftOp.getOperation(), shiftOp.getOrigins());
800 } else if (auto shapeShiftOp = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(
801 v.getDefiningOp())) {
802 return insertAdjustments(shapeShiftOp.getOperation(),
803 shapeShiftOp.getOrigins());
806 return std::nullopt;
810 void fir::ArrayCoorOp::getCanonicalizationPatterns(
811 mlir::RewritePatternSet &patterns, mlir::MLIRContext *context) {
812 // TODO: !fir.shape<1> operand may be removed from array_coor always.
813 patterns.add<SimplifyArrayCoorOp>(context);
816 //===----------------------------------------------------------------------===//
817 // ArrayLoadOp
818 //===----------------------------------------------------------------------===//
820 static mlir::Type adjustedElementType(mlir::Type t) {
821 if (auto ty = mlir::dyn_cast<fir::ReferenceType>(t)) {
822 auto eleTy = ty.getEleTy();
823 if (fir::isa_char(eleTy))
824 return eleTy;
825 if (fir::isa_derived(eleTy))
826 return eleTy;
827 if (mlir::isa<fir::SequenceType>(eleTy))
828 return eleTy;
830 return t;
833 std::vector<mlir::Value> fir::ArrayLoadOp::getExtents() {
834 if (auto sh = getShape())
835 if (auto *op = sh.getDefiningOp()) {
836 if (auto shOp = mlir::dyn_cast<fir::ShapeOp>(op)) {
837 auto extents = shOp.getExtents();
838 return {extents.begin(), extents.end()};
840 return mlir::cast<fir::ShapeShiftOp>(op).getExtents();
842 return {};
845 llvm::LogicalResult fir::ArrayLoadOp::verify() {
846 auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
847 auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);
848 if (!arrTy)
849 return emitOpError("must be a reference to an array");
850 auto arrDim = arrTy.getDimension();
852 if (auto shapeOp = getShape()) {
853 auto shapeTy = shapeOp.getType();
854 unsigned shapeTyRank = 0u;
855 if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy)) {
856 shapeTyRank = s.getRank();
857 } else if (auto ss = mlir::dyn_cast<fir::ShapeShiftType>(shapeTy)) {
858 shapeTyRank = ss.getRank();
859 } else {
860 auto s = mlir::cast<fir::ShiftType>(shapeTy);
861 shapeTyRank = s.getRank();
862 if (!mlir::isa<fir::BaseBoxType>(getMemref().getType()))
863 return emitOpError("shift can only be provided with fir.box memref");
865 if (arrDim && arrDim != shapeTyRank)
866 return emitOpError("rank of dimension mismatched");
869 if (auto sliceOp = getSlice()) {
870 if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))
871 if (!sl.getSubstr().empty())
872 return emitOpError("array_load cannot take a slice with substring");
873 if (auto sliceTy = mlir::dyn_cast<fir::SliceType>(sliceOp.getType()))
874 if (sliceTy.getRank() != arrDim)
875 return emitOpError("rank of dimension in slice mismatched");
878 if (!validTypeParams(getMemref().getType(), getTypeparams()))
879 return emitOpError("invalid type parameters");
881 return mlir::success();
884 //===----------------------------------------------------------------------===//
885 // ArrayMergeStoreOp
886 //===----------------------------------------------------------------------===//
888 llvm::LogicalResult fir::ArrayMergeStoreOp::verify() {
889 if (!mlir::isa<fir::ArrayLoadOp>(getOriginal().getDefiningOp()))
890 return emitOpError("operand #0 must be result of a fir.array_load op");
891 if (auto sl = getSlice()) {
892 if (auto sliceOp =
893 mlir::dyn_cast_or_null<fir::SliceOp>(sl.getDefiningOp())) {
894 if (!sliceOp.getSubstr().empty())
895 return emitOpError(
896 "array_merge_store cannot take a slice with substring");
897 if (!sliceOp.getFields().empty()) {
898 // This is an intra-object merge, where the slice is projecting the
899 // subfields that are to be overwritten by the merge operation.
900 auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
901 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {
902 auto projTy =
903 fir::applyPathToType(seqTy.getEleTy(), sliceOp.getFields());
904 if (fir::unwrapSequenceType(getOriginal().getType()) != projTy)
905 return emitOpError(
906 "type of origin does not match sliced memref type");
907 if (fir::unwrapSequenceType(getSequence().getType()) != projTy)
908 return emitOpError(
909 "type of sequence does not match sliced memref type");
910 return mlir::success();
912 return emitOpError("referenced type is not an array");
915 return mlir::success();
917 auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
918 if (getOriginal().getType() != eleTy)
919 return emitOpError("type of origin does not match memref element type");
920 if (getSequence().getType() != eleTy)
921 return emitOpError("type of sequence does not match memref element type");
922 if (!validTypeParams(getMemref().getType(), getTypeparams()))
923 return emitOpError("invalid type parameters");
924 return mlir::success();
927 //===----------------------------------------------------------------------===//
928 // ArrayFetchOp
929 //===----------------------------------------------------------------------===//
931 // Template function used for both array_fetch and array_update verification.
932 template <typename A>
933 mlir::Type validArraySubobject(A op) {
934 auto ty = op.getSequence().getType();
935 return fir::applyPathToType(ty, op.getIndices());
938 llvm::LogicalResult fir::ArrayFetchOp::verify() {
939 auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
940 auto indSize = getIndices().size();
941 if (indSize < arrTy.getDimension())
942 return emitOpError("number of indices != dimension of array");
943 if (indSize == arrTy.getDimension() &&
944 ::adjustedElementType(getElement().getType()) != arrTy.getEleTy())
945 return emitOpError("return type does not match array");
946 auto ty = validArraySubobject(*this);
947 if (!ty || ty != ::adjustedElementType(getType()))
948 return emitOpError("return type and/or indices do not type check");
949 if (!mlir::isa<fir::ArrayLoadOp>(getSequence().getDefiningOp()))
950 return emitOpError("argument #0 must be result of fir.array_load");
951 if (!validTypeParams(arrTy, getTypeparams()))
952 return emitOpError("invalid type parameters");
953 return mlir::success();
956 //===----------------------------------------------------------------------===//
957 // ArrayAccessOp
958 //===----------------------------------------------------------------------===//
960 llvm::LogicalResult fir::ArrayAccessOp::verify() {
961 auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
962 std::size_t indSize = getIndices().size();
963 if (indSize < arrTy.getDimension())
964 return emitOpError("number of indices != dimension of array");
965 if (indSize == arrTy.getDimension() &&
966 getElement().getType() != fir::ReferenceType::get(arrTy.getEleTy()))
967 return emitOpError("return type does not match array");
968 mlir::Type ty = validArraySubobject(*this);
969 if (!ty || fir::ReferenceType::get(ty) != getType())
970 return emitOpError("return type and/or indices do not type check");
971 if (!validTypeParams(arrTy, getTypeparams()))
972 return emitOpError("invalid type parameters");
973 return mlir::success();
976 //===----------------------------------------------------------------------===//
977 // ArrayUpdateOp
978 //===----------------------------------------------------------------------===//
980 llvm::LogicalResult fir::ArrayUpdateOp::verify() {
981 if (fir::isa_ref_type(getMerge().getType()))
982 return emitOpError("does not support reference type for merge");
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(getMerge().getType()) != arrTy.getEleTy())
989 return emitOpError("merged value does not have element type");
990 auto ty = validArraySubobject(*this);
991 if (!ty || ty != ::adjustedElementType(getMerge().getType()))
992 return emitOpError("merged value and/or indices do not type check");
993 if (!validTypeParams(arrTy, getTypeparams()))
994 return emitOpError("invalid type parameters");
995 return mlir::success();
998 //===----------------------------------------------------------------------===//
999 // ArrayModifyOp
1000 //===----------------------------------------------------------------------===//
1002 llvm::LogicalResult fir::ArrayModifyOp::verify() {
1003 auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());
1004 auto indSize = getIndices().size();
1005 if (indSize < arrTy.getDimension())
1006 return emitOpError("number of indices must match array dimension");
1007 return mlir::success();
1010 //===----------------------------------------------------------------------===//
1011 // BoxAddrOp
1012 //===----------------------------------------------------------------------===//
1014 void fir::BoxAddrOp::build(mlir::OpBuilder &builder,
1015 mlir::OperationState &result, mlir::Value val) {
1016 mlir::Type type =
1017 llvm::TypeSwitch<mlir::Type, mlir::Type>(val.getType())
1018 .Case<fir::BaseBoxType>([&](fir::BaseBoxType ty) -> mlir::Type {
1019 mlir::Type eleTy = ty.getEleTy();
1020 if (fir::isa_ref_type(eleTy))
1021 return eleTy;
1022 return fir::ReferenceType::get(eleTy);
1024 .Case<fir::BoxCharType>([&](fir::BoxCharType ty) -> mlir::Type {
1025 return fir::ReferenceType::get(ty.getEleTy());
1027 .Case<fir::BoxProcType>(
1028 [&](fir::BoxProcType ty) { return ty.getEleTy(); })
1029 .Default([&](const auto &) { return mlir::Type{}; });
1030 assert(type && "bad val type");
1031 build(builder, result, type, val);
1034 mlir::OpFoldResult fir::BoxAddrOp::fold(FoldAdaptor adaptor) {
1035 if (auto *v = getVal().getDefiningOp()) {
1036 if (auto box = mlir::dyn_cast<fir::EmboxOp>(v)) {
1037 // Fold only if not sliced
1038 if (!box.getSlice() && box.getMemref().getType() == getType()) {
1039 propagateAttributes(getOperation(), box.getMemref().getDefiningOp());
1040 return box.getMemref();
1043 if (auto box = mlir::dyn_cast<fir::EmboxCharOp>(v))
1044 if (box.getMemref().getType() == getType())
1045 return box.getMemref();
1047 return {};
1050 //===----------------------------------------------------------------------===//
1051 // BoxCharLenOp
1052 //===----------------------------------------------------------------------===//
1054 mlir::OpFoldResult fir::BoxCharLenOp::fold(FoldAdaptor adaptor) {
1055 if (auto v = getVal().getDefiningOp()) {
1056 if (auto box = mlir::dyn_cast<fir::EmboxCharOp>(v))
1057 return box.getLen();
1059 return {};
1062 //===----------------------------------------------------------------------===//
1063 // BoxDimsOp
1064 //===----------------------------------------------------------------------===//
1066 /// Get the result types packed in a tuple tuple
1067 mlir::Type fir::BoxDimsOp::getTupleType() {
1068 // note: triple, but 4 is nearest power of 2
1069 llvm::SmallVector<mlir::Type> triple{
1070 getResult(0).getType(), getResult(1).getType(), getResult(2).getType()};
1071 return mlir::TupleType::get(getContext(), triple);
1074 //===----------------------------------------------------------------------===//
1075 // BoxRankOp
1076 //===----------------------------------------------------------------------===//
1078 void fir::BoxRankOp::getEffects(
1079 llvm::SmallVectorImpl<
1080 mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1081 &effects) {
1082 mlir::OpOperand &inputBox = getBoxMutable();
1083 if (fir::isBoxAddress(inputBox.get().getType()))
1084 effects.emplace_back(mlir::MemoryEffects::Read::get(), &inputBox,
1085 mlir::SideEffects::DefaultResource::get());
1088 //===----------------------------------------------------------------------===//
1089 // CallOp
1090 //===----------------------------------------------------------------------===//
1092 mlir::FunctionType fir::CallOp::getFunctionType() {
1093 return mlir::FunctionType::get(getContext(), getOperandTypes(),
1094 getResultTypes());
1097 void fir::CallOp::print(mlir::OpAsmPrinter &p) {
1098 bool isDirect = getCallee().has_value();
1099 p << ' ';
1100 if (isDirect)
1101 p << *getCallee();
1102 else
1103 p << getOperand(0);
1104 p << '(' << (*this)->getOperands().drop_front(isDirect ? 0 : 1) << ')';
1106 // Print `proc_attrs<...>`, if present.
1107 fir::FortranProcedureFlagsEnumAttr procAttrs = getProcedureAttrsAttr();
1108 if (procAttrs &&
1109 procAttrs.getValue() != fir::FortranProcedureFlagsEnum::none) {
1110 p << ' ' << fir::FortranProcedureFlagsEnumAttr::getMnemonic();
1111 p.printStrippedAttrOrType(procAttrs);
1114 // Print 'fastmath<...>' (if it has non-default value) before
1115 // any other attributes.
1116 mlir::arith::FastMathFlagsAttr fmfAttr = getFastmathAttr();
1117 if (fmfAttr.getValue() != mlir::arith::FastMathFlags::none) {
1118 p << ' ' << mlir::arith::FastMathFlagsAttr::getMnemonic();
1119 p.printStrippedAttrOrType(fmfAttr);
1122 p.printOptionalAttrDict((*this)->getAttrs(),
1123 {fir::CallOp::getCalleeAttrNameStr(),
1124 getFastmathAttrName(), getProcedureAttrsAttrName()});
1125 auto resultTypes{getResultTypes()};
1126 llvm::SmallVector<mlir::Type> argTypes(
1127 llvm::drop_begin(getOperandTypes(), isDirect ? 0 : 1));
1128 p << " : " << mlir::FunctionType::get(getContext(), argTypes, resultTypes);
1131 mlir::ParseResult fir::CallOp::parse(mlir::OpAsmParser &parser,
1132 mlir::OperationState &result) {
1133 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
1134 if (parser.parseOperandList(operands))
1135 return mlir::failure();
1137 mlir::NamedAttrList attrs;
1138 mlir::SymbolRefAttr funcAttr;
1139 bool isDirect = operands.empty();
1140 if (isDirect)
1141 if (parser.parseAttribute(funcAttr, fir::CallOp::getCalleeAttrNameStr(),
1142 attrs))
1143 return mlir::failure();
1145 mlir::Type type;
1146 if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::Paren))
1147 return mlir::failure();
1149 // Parse `proc_attrs<...>`, if present.
1150 fir::FortranProcedureFlagsEnumAttr procAttr;
1151 if (mlir::succeeded(parser.parseOptionalKeyword(
1152 fir::FortranProcedureFlagsEnumAttr::getMnemonic())))
1153 if (parser.parseCustomAttributeWithFallback(
1154 procAttr, mlir::Type{}, getProcedureAttrsAttrName(result.name),
1155 attrs))
1156 return mlir::failure();
1158 // Parse 'fastmath<...>', if present.
1159 mlir::arith::FastMathFlagsAttr fmfAttr;
1160 llvm::StringRef fmfAttrName = getFastmathAttrName(result.name);
1161 if (mlir::succeeded(parser.parseOptionalKeyword(fmfAttrName)))
1162 if (parser.parseCustomAttributeWithFallback(fmfAttr, mlir::Type{},
1163 fmfAttrName, attrs))
1164 return mlir::failure();
1166 if (parser.parseOptionalAttrDict(attrs) || parser.parseColon() ||
1167 parser.parseType(type))
1168 return mlir::failure();
1170 auto funcType = mlir::dyn_cast<mlir::FunctionType>(type);
1171 if (!funcType)
1172 return parser.emitError(parser.getNameLoc(), "expected function type");
1173 if (isDirect) {
1174 if (parser.resolveOperands(operands, funcType.getInputs(),
1175 parser.getNameLoc(), result.operands))
1176 return mlir::failure();
1177 } else {
1178 auto funcArgs =
1179 llvm::ArrayRef<mlir::OpAsmParser::UnresolvedOperand>(operands)
1180 .drop_front();
1181 if (parser.resolveOperand(operands[0], funcType, result.operands) ||
1182 parser.resolveOperands(funcArgs, funcType.getInputs(),
1183 parser.getNameLoc(), result.operands))
1184 return mlir::failure();
1186 result.addTypes(funcType.getResults());
1187 result.attributes = attrs;
1188 return mlir::success();
1191 void fir::CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
1192 mlir::func::FuncOp callee, mlir::ValueRange operands) {
1193 result.addOperands(operands);
1194 result.addAttribute(getCalleeAttrNameStr(), mlir::SymbolRefAttr::get(callee));
1195 result.addTypes(callee.getFunctionType().getResults());
1198 void fir::CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
1199 mlir::SymbolRefAttr callee,
1200 llvm::ArrayRef<mlir::Type> results,
1201 mlir::ValueRange operands) {
1202 result.addOperands(operands);
1203 if (callee)
1204 result.addAttribute(getCalleeAttrNameStr(), callee);
1205 result.addTypes(results);
1208 //===----------------------------------------------------------------------===//
1209 // CharConvertOp
1210 //===----------------------------------------------------------------------===//
1212 llvm::LogicalResult fir::CharConvertOp::verify() {
1213 auto unwrap = [&](mlir::Type t) {
1214 t = fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t));
1215 return mlir::dyn_cast<fir::CharacterType>(t);
1217 auto inTy = unwrap(getFrom().getType());
1218 auto outTy = unwrap(getTo().getType());
1219 if (!(inTy && outTy))
1220 return emitOpError("not a reference to a character");
1221 if (inTy.getFKind() == outTy.getFKind())
1222 return emitOpError("buffers must have different KIND values");
1223 return mlir::success();
1226 //===----------------------------------------------------------------------===//
1227 // CmpOp
1228 //===----------------------------------------------------------------------===//
1230 template <typename OPTY>
1231 static void printCmpOp(mlir::OpAsmPrinter &p, OPTY op) {
1232 p << ' ';
1233 auto predSym = mlir::arith::symbolizeCmpFPredicate(
1234 op->template getAttrOfType<mlir::IntegerAttr>(
1235 OPTY::getPredicateAttrName())
1236 .getInt());
1237 assert(predSym.has_value() && "invalid symbol value for predicate");
1238 p << '"' << mlir::arith::stringifyCmpFPredicate(predSym.value()) << '"'
1239 << ", ";
1240 p.printOperand(op.getLhs());
1241 p << ", ";
1242 p.printOperand(op.getRhs());
1243 p.printOptionalAttrDict(op->getAttrs(),
1244 /*elidedAttrs=*/{OPTY::getPredicateAttrName()});
1245 p << " : " << op.getLhs().getType();
1248 template <typename OPTY>
1249 static mlir::ParseResult parseCmpOp(mlir::OpAsmParser &parser,
1250 mlir::OperationState &result) {
1251 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> ops;
1252 mlir::NamedAttrList attrs;
1253 mlir::Attribute predicateNameAttr;
1254 mlir::Type type;
1255 if (parser.parseAttribute(predicateNameAttr, OPTY::getPredicateAttrName(),
1256 attrs) ||
1257 parser.parseComma() || parser.parseOperandList(ops, 2) ||
1258 parser.parseOptionalAttrDict(attrs) || parser.parseColonType(type) ||
1259 parser.resolveOperands(ops, type, result.operands))
1260 return mlir::failure();
1262 if (!mlir::isa<mlir::StringAttr>(predicateNameAttr))
1263 return parser.emitError(parser.getNameLoc(),
1264 "expected string comparison predicate attribute");
1266 // Rewrite string attribute to an enum value.
1267 llvm::StringRef predicateName =
1268 mlir::cast<mlir::StringAttr>(predicateNameAttr).getValue();
1269 auto predicate = fir::CmpcOp::getPredicateByName(predicateName);
1270 auto builder = parser.getBuilder();
1271 mlir::Type i1Type = builder.getI1Type();
1272 attrs.set(OPTY::getPredicateAttrName(),
1273 builder.getI64IntegerAttr(static_cast<std::int64_t>(predicate)));
1274 result.attributes = attrs;
1275 result.addTypes({i1Type});
1276 return mlir::success();
1279 //===----------------------------------------------------------------------===//
1280 // CmpcOp
1281 //===----------------------------------------------------------------------===//
1283 void fir::buildCmpCOp(mlir::OpBuilder &builder, mlir::OperationState &result,
1284 mlir::arith::CmpFPredicate predicate, mlir::Value lhs,
1285 mlir::Value rhs) {
1286 result.addOperands({lhs, rhs});
1287 result.types.push_back(builder.getI1Type());
1288 result.addAttribute(
1289 fir::CmpcOp::getPredicateAttrName(),
1290 builder.getI64IntegerAttr(static_cast<std::int64_t>(predicate)));
1293 mlir::arith::CmpFPredicate
1294 fir::CmpcOp::getPredicateByName(llvm::StringRef name) {
1295 auto pred = mlir::arith::symbolizeCmpFPredicate(name);
1296 assert(pred.has_value() && "invalid predicate name");
1297 return pred.value();
1300 void fir::CmpcOp::print(mlir::OpAsmPrinter &p) { printCmpOp(p, *this); }
1302 mlir::ParseResult fir::CmpcOp::parse(mlir::OpAsmParser &parser,
1303 mlir::OperationState &result) {
1304 return parseCmpOp<fir::CmpcOp>(parser, result);
1307 //===----------------------------------------------------------------------===//
1308 // ConvertOp
1309 //===----------------------------------------------------------------------===//
1311 void fir::ConvertOp::getCanonicalizationPatterns(
1312 mlir::RewritePatternSet &results, mlir::MLIRContext *context) {
1313 results.insert<ConvertConvertOptPattern, ConvertAscendingIndexOptPattern,
1314 ConvertDescendingIndexOptPattern, RedundantConvertOptPattern,
1315 CombineConvertOptPattern, CombineConvertTruncOptPattern,
1316 ForwardConstantConvertPattern>(context);
1319 mlir::OpFoldResult fir::ConvertOp::fold(FoldAdaptor adaptor) {
1320 if (getValue().getType() == getType())
1321 return getValue();
1322 if (matchPattern(getValue(), mlir::m_Op<fir::ConvertOp>())) {
1323 auto inner = mlir::cast<fir::ConvertOp>(getValue().getDefiningOp());
1324 // (convert (convert 'a : logical -> i1) : i1 -> logical) ==> forward 'a
1325 if (auto toTy = mlir::dyn_cast<fir::LogicalType>(getType()))
1326 if (auto fromTy =
1327 mlir::dyn_cast<fir::LogicalType>(inner.getValue().getType()))
1328 if (mlir::isa<mlir::IntegerType>(inner.getType()) && (toTy == fromTy))
1329 return inner.getValue();
1330 // (convert (convert 'a : i1 -> logical) : logical -> i1) ==> forward 'a
1331 if (auto toTy = mlir::dyn_cast<mlir::IntegerType>(getType()))
1332 if (auto fromTy =
1333 mlir::dyn_cast<mlir::IntegerType>(inner.getValue().getType()))
1334 if (mlir::isa<fir::LogicalType>(inner.getType()) && (toTy == fromTy) &&
1335 (fromTy.getWidth() == 1))
1336 return inner.getValue();
1338 return {};
1341 bool fir::ConvertOp::isInteger(mlir::Type ty) {
1342 return mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType>(ty);
1345 bool fir::ConvertOp::isIntegerCompatible(mlir::Type ty) {
1346 return isInteger(ty) || mlir::isa<fir::LogicalType>(ty);
1349 bool fir::ConvertOp::isFloatCompatible(mlir::Type ty) {
1350 return mlir::isa<mlir::FloatType>(ty);
1353 bool fir::ConvertOp::isPointerCompatible(mlir::Type ty) {
1354 return mlir::isa<fir::ReferenceType, fir::PointerType, fir::HeapType,
1355 fir::LLVMPointerType, mlir::MemRefType, mlir::FunctionType,
1356 fir::TypeDescType, mlir::LLVM::LLVMPointerType>(ty);
1359 static std::optional<mlir::Type> getVectorElementType(mlir::Type ty) {
1360 mlir::Type elemTy;
1361 if (mlir::isa<fir::VectorType>(ty))
1362 elemTy = mlir::dyn_cast<fir::VectorType>(ty).getElementType();
1363 else if (mlir::isa<mlir::VectorType>(ty))
1364 elemTy = mlir::dyn_cast<mlir::VectorType>(ty).getElementType();
1365 else
1366 return std::nullopt;
1368 // e.g. fir.vector<4:ui32> => mlir.vector<4xi32>
1369 // e.g. mlir.vector<4xui32> => mlir.vector<4xi32>
1370 if (elemTy.isUnsignedInteger()) {
1371 elemTy = mlir::IntegerType::get(
1372 ty.getContext(), mlir::dyn_cast<mlir::IntegerType>(elemTy).getWidth());
1374 return elemTy;
1377 static std::optional<uint64_t> getVectorLen(mlir::Type ty) {
1378 if (mlir::isa<fir::VectorType>(ty))
1379 return mlir::dyn_cast<fir::VectorType>(ty).getLen();
1380 else if (mlir::isa<mlir::VectorType>(ty)) {
1381 // fir.vector only supports 1-D vector
1382 if (!(mlir::dyn_cast<mlir::VectorType>(ty).isScalable()))
1383 return mlir::dyn_cast<mlir::VectorType>(ty).getShape()[0];
1386 return std::nullopt;
1389 bool fir::ConvertOp::areVectorsCompatible(mlir::Type inTy, mlir::Type outTy) {
1390 if (!(mlir::isa<fir::VectorType>(inTy) &&
1391 mlir::isa<mlir::VectorType>(outTy)) &&
1392 !(mlir::isa<mlir::VectorType>(inTy) && mlir::isa<fir::VectorType>(outTy)))
1393 return false;
1395 // Only support integer, unsigned and real vector
1396 // Both vectors must have the same element type
1397 std::optional<mlir::Type> inElemTy = getVectorElementType(inTy);
1398 std::optional<mlir::Type> outElemTy = getVectorElementType(outTy);
1399 if (!inElemTy.has_value() || !outElemTy.has_value() ||
1400 inElemTy.value() != outElemTy.value())
1401 return false;
1403 // Both vectors must have the same number of elements
1404 std::optional<uint64_t> inLen = getVectorLen(inTy);
1405 std::optional<uint64_t> outLen = getVectorLen(outTy);
1406 if (!inLen.has_value() || !outLen.has_value() ||
1407 inLen.value() != outLen.value())
1408 return false;
1410 return true;
1413 static bool areRecordsCompatible(mlir::Type inTy, mlir::Type outTy) {
1414 // Both records must have the same field types.
1415 // Trust frontend semantics for in-depth checks, such as if both records
1416 // have the BIND(C) attribute.
1417 auto inRecTy = mlir::dyn_cast<fir::RecordType>(inTy);
1418 auto outRecTy = mlir::dyn_cast<fir::RecordType>(outTy);
1419 return inRecTy && outRecTy && inRecTy.getTypeList() == outRecTy.getTypeList();
1422 bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
1423 if (inType == outType)
1424 return true;
1425 return (isPointerCompatible(inType) && isPointerCompatible(outType)) ||
1426 (isIntegerCompatible(inType) && isIntegerCompatible(outType)) ||
1427 (isInteger(inType) && isFloatCompatible(outType)) ||
1428 (isFloatCompatible(inType) && isInteger(outType)) ||
1429 (isFloatCompatible(inType) && isFloatCompatible(outType)) ||
1430 (isIntegerCompatible(inType) && isPointerCompatible(outType)) ||
1431 (isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
1432 (mlir::isa<fir::BoxType>(inType) &&
1433 mlir::isa<fir::BoxType>(outType)) ||
1434 (mlir::isa<fir::BoxProcType>(inType) &&
1435 mlir::isa<fir::BoxProcType>(outType)) ||
1436 (fir::isa_complex(inType) && fir::isa_complex(outType)) ||
1437 (fir::isBoxedRecordType(inType) && fir::isPolymorphicType(outType)) ||
1438 (fir::isPolymorphicType(inType) && fir::isPolymorphicType(outType)) ||
1439 (fir::isPolymorphicType(inType) && mlir::isa<BoxType>(outType)) ||
1440 areVectorsCompatible(inType, outType) ||
1441 areRecordsCompatible(inType, outType);
1444 llvm::LogicalResult fir::ConvertOp::verify() {
1445 if (canBeConverted(getValue().getType(), getType()))
1446 return mlir::success();
1447 return emitOpError("invalid type conversion")
1448 << getValue().getType() << " / " << getType();
1451 //===----------------------------------------------------------------------===//
1452 // CoordinateOp
1453 //===----------------------------------------------------------------------===//
1455 void fir::CoordinateOp::print(mlir::OpAsmPrinter &p) {
1456 p << ' ' << getRef() << ", " << getCoor();
1457 p.printOptionalAttrDict((*this)->getAttrs(), /*elideAttrs=*/{"baseType"});
1458 p << " : ";
1459 p.printFunctionalType(getOperandTypes(), (*this)->getResultTypes());
1462 mlir::ParseResult fir::CoordinateOp::parse(mlir::OpAsmParser &parser,
1463 mlir::OperationState &result) {
1464 mlir::OpAsmParser::UnresolvedOperand memref;
1465 if (parser.parseOperand(memref) || parser.parseComma())
1466 return mlir::failure();
1467 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> coorOperands;
1468 if (parser.parseOperandList(coorOperands))
1469 return mlir::failure();
1470 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> allOperands;
1471 allOperands.push_back(memref);
1472 allOperands.append(coorOperands.begin(), coorOperands.end());
1473 mlir::FunctionType funcTy;
1474 auto loc = parser.getCurrentLocation();
1475 if (parser.parseOptionalAttrDict(result.attributes) ||
1476 parser.parseColonType(funcTy) ||
1477 parser.resolveOperands(allOperands, funcTy.getInputs(), loc,
1478 result.operands) ||
1479 parser.addTypesToList(funcTy.getResults(), result.types))
1480 return mlir::failure();
1481 result.addAttribute("baseType", mlir::TypeAttr::get(funcTy.getInput(0)));
1482 return mlir::success();
1485 llvm::LogicalResult fir::CoordinateOp::verify() {
1486 const mlir::Type refTy = getRef().getType();
1487 if (fir::isa_ref_type(refTy)) {
1488 auto eleTy = fir::dyn_cast_ptrEleTy(refTy);
1489 if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {
1490 if (arrTy.hasUnknownShape())
1491 return emitOpError("cannot find coordinate in unknown shape");
1492 if (arrTy.getConstantRows() < arrTy.getDimension() - 1)
1493 return emitOpError("cannot find coordinate with unknown extents");
1495 if (!(fir::isa_aggregate(eleTy) || fir::isa_complex(eleTy) ||
1496 fir::isa_char_string(eleTy)))
1497 return emitOpError("cannot apply to this element type");
1499 auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(refTy);
1500 unsigned dimension = 0;
1501 const unsigned numCoors = getCoor().size();
1502 for (auto coorOperand : llvm::enumerate(getCoor())) {
1503 auto co = coorOperand.value();
1504 if (dimension == 0 && mlir::isa<fir::SequenceType>(eleTy)) {
1505 dimension = mlir::cast<fir::SequenceType>(eleTy).getDimension();
1506 if (dimension == 0)
1507 return emitOpError("cannot apply to array of unknown rank");
1509 if (auto *defOp = co.getDefiningOp()) {
1510 if (auto index = mlir::dyn_cast<fir::LenParamIndexOp>(defOp)) {
1511 // Recovering a LEN type parameter only makes sense from a boxed
1512 // value. For a bare reference, the LEN type parameters must be
1513 // passed as additional arguments to `index`.
1514 if (mlir::isa<fir::BoxType>(refTy)) {
1515 if (coorOperand.index() != numCoors - 1)
1516 return emitOpError("len_param_index must be last argument");
1517 if (getNumOperands() != 2)
1518 return emitOpError("too many operands for len_param_index case");
1520 if (eleTy != index.getOnType())
1521 emitOpError(
1522 "len_param_index type not compatible with reference type");
1523 return mlir::success();
1524 } else if (auto index = mlir::dyn_cast<fir::FieldIndexOp>(defOp)) {
1525 if (eleTy != index.getOnType())
1526 emitOpError("field_index type not compatible with reference type");
1527 if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy)) {
1528 eleTy = recTy.getType(index.getFieldName());
1529 continue;
1531 return emitOpError("field_index not applied to !fir.type");
1534 if (dimension) {
1535 if (--dimension == 0)
1536 eleTy = mlir::cast<fir::SequenceType>(eleTy).getElementType();
1537 } else {
1538 if (auto t = mlir::dyn_cast<mlir::TupleType>(eleTy)) {
1539 // FIXME: Generally, we don't know which field of the tuple is being
1540 // referred to unless the operand is a constant. Just assume everything
1541 // is good in the tuple case for now.
1542 return mlir::success();
1543 } else if (auto t = mlir::dyn_cast<fir::RecordType>(eleTy)) {
1544 // FIXME: This is the same as the tuple case.
1545 return mlir::success();
1546 } else if (auto t = mlir::dyn_cast<mlir::ComplexType>(eleTy)) {
1547 eleTy = t.getElementType();
1548 } else if (auto t = mlir::dyn_cast<fir::CharacterType>(eleTy)) {
1549 if (t.getLen() == fir::CharacterType::singleton())
1550 return emitOpError("cannot apply to character singleton");
1551 eleTy = fir::CharacterType::getSingleton(t.getContext(), t.getFKind());
1552 if (fir::unwrapRefType(getType()) != eleTy)
1553 return emitOpError("character type mismatch");
1554 } else {
1555 return emitOpError("invalid parameters (too many)");
1559 return mlir::success();
1562 //===----------------------------------------------------------------------===//
1563 // DispatchOp
1564 //===----------------------------------------------------------------------===//
1566 llvm::LogicalResult fir::DispatchOp::verify() {
1567 // Check that pass_arg_pos is in range of actual operands. pass_arg_pos is
1568 // unsigned so check for less than zero is not needed.
1569 if (getPassArgPos() && *getPassArgPos() > (getArgOperands().size() - 1))
1570 return emitOpError(
1571 "pass_arg_pos must be smaller than the number of operands");
1573 // Operand pointed by pass_arg_pos must have polymorphic type.
1574 if (getPassArgPos() &&
1575 !fir::isPolymorphicType(getArgOperands()[*getPassArgPos()].getType()))
1576 return emitOpError("pass_arg_pos must be a polymorphic operand");
1577 return mlir::success();
1580 mlir::FunctionType fir::DispatchOp::getFunctionType() {
1581 return mlir::FunctionType::get(getContext(), getOperandTypes(),
1582 getResultTypes());
1585 //===----------------------------------------------------------------------===//
1586 // TypeInfoOp
1587 //===----------------------------------------------------------------------===//
1589 void fir::TypeInfoOp::build(mlir::OpBuilder &builder,
1590 mlir::OperationState &result, fir::RecordType type,
1591 fir::RecordType parentType,
1592 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1593 result.addRegion();
1594 result.addRegion();
1595 result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
1596 builder.getStringAttr(type.getName()));
1597 result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type));
1598 if (parentType)
1599 result.addAttribute(getParentTypeAttrName(result.name),
1600 mlir::TypeAttr::get(parentType));
1601 result.addAttributes(attrs);
1604 llvm::LogicalResult fir::TypeInfoOp::verify() {
1605 if (!getDispatchTable().empty())
1606 for (auto &op : getDispatchTable().front().without_terminator())
1607 if (!mlir::isa<fir::DTEntryOp>(op))
1608 return op.emitOpError("dispatch table must contain dt_entry");
1610 if (!mlir::isa<fir::RecordType>(getType()))
1611 return emitOpError("type must be a fir.type");
1613 if (getParentType() && !mlir::isa<fir::RecordType>(*getParentType()))
1614 return emitOpError("parent_type must be a fir.type");
1615 return mlir::success();
1618 //===----------------------------------------------------------------------===//
1619 // EmboxOp
1620 //===----------------------------------------------------------------------===//
1622 llvm::LogicalResult fir::EmboxOp::verify() {
1623 auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());
1624 bool isArray = false;
1625 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {
1626 eleTy = seqTy.getEleTy();
1627 isArray = true;
1629 if (hasLenParams()) {
1630 auto lenPs = numLenParams();
1631 if (auto rt = mlir::dyn_cast<fir::RecordType>(eleTy)) {
1632 if (lenPs != rt.getNumLenParams())
1633 return emitOpError("number of LEN params does not correspond"
1634 " to the !fir.type type");
1635 } else if (auto strTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) {
1636 if (strTy.getLen() != fir::CharacterType::unknownLen())
1637 return emitOpError("CHARACTER already has static LEN");
1638 } else {
1639 return emitOpError("LEN parameters require CHARACTER or derived type");
1641 for (auto lp : getTypeparams())
1642 if (!fir::isa_integer(lp.getType()))
1643 return emitOpError("LEN parameters must be integral type");
1645 if (getShape() && !isArray)
1646 return emitOpError("shape must not be provided for a scalar");
1647 if (getSlice() && !isArray)
1648 return emitOpError("slice must not be provided for a scalar");
1649 if (getSourceBox() && !mlir::isa<fir::ClassType>(getResult().getType()))
1650 return emitOpError("source_box must be used with fir.class result type");
1651 return mlir::success();
1654 //===----------------------------------------------------------------------===//
1655 // EmboxCharOp
1656 //===----------------------------------------------------------------------===//
1658 llvm::LogicalResult fir::EmboxCharOp::verify() {
1659 auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());
1660 if (!mlir::dyn_cast_or_null<fir::CharacterType>(eleTy))
1661 return mlir::failure();
1662 return mlir::success();
1665 //===----------------------------------------------------------------------===//
1666 // EmboxProcOp
1667 //===----------------------------------------------------------------------===//
1669 llvm::LogicalResult fir::EmboxProcOp::verify() {
1670 // host bindings (optional) must be a reference to a tuple
1671 if (auto h = getHost()) {
1672 if (auto r = mlir::dyn_cast<fir::ReferenceType>(h.getType()))
1673 if (mlir::isa<mlir::TupleType>(r.getEleTy()))
1674 return mlir::success();
1675 return mlir::failure();
1677 return mlir::success();
1680 //===----------------------------------------------------------------------===//
1681 // TypeDescOp
1682 //===----------------------------------------------------------------------===//
1684 void fir::TypeDescOp::build(mlir::OpBuilder &, mlir::OperationState &result,
1685 mlir::TypeAttr inty) {
1686 result.addAttribute("in_type", inty);
1687 result.addTypes(TypeDescType::get(inty.getValue()));
1690 mlir::ParseResult fir::TypeDescOp::parse(mlir::OpAsmParser &parser,
1691 mlir::OperationState &result) {
1692 mlir::Type intype;
1693 if (parser.parseType(intype))
1694 return mlir::failure();
1695 result.addAttribute("in_type", mlir::TypeAttr::get(intype));
1696 mlir::Type restype = fir::TypeDescType::get(intype);
1697 if (parser.addTypeToList(restype, result.types))
1698 return mlir::failure();
1699 return mlir::success();
1702 void fir::TypeDescOp::print(mlir::OpAsmPrinter &p) {
1703 p << ' ' << getOperation()->getAttr("in_type");
1704 p.printOptionalAttrDict(getOperation()->getAttrs(), {"in_type"});
1707 llvm::LogicalResult fir::TypeDescOp::verify() {
1708 mlir::Type resultTy = getType();
1709 if (auto tdesc = mlir::dyn_cast<fir::TypeDescType>(resultTy)) {
1710 if (tdesc.getOfTy() != getInType())
1711 return emitOpError("wrapped type mismatched");
1712 return mlir::success();
1714 return emitOpError("must be !fir.tdesc type");
1717 //===----------------------------------------------------------------------===//
1718 // GlobalOp
1719 //===----------------------------------------------------------------------===//
1721 mlir::Type fir::GlobalOp::resultType() {
1722 return wrapAllocaResultType(getType());
1725 mlir::ParseResult fir::GlobalOp::parse(mlir::OpAsmParser &parser,
1726 mlir::OperationState &result) {
1727 // Parse the optional linkage
1728 llvm::StringRef linkage;
1729 auto &builder = parser.getBuilder();
1730 if (mlir::succeeded(parser.parseOptionalKeyword(&linkage))) {
1731 if (fir::GlobalOp::verifyValidLinkage(linkage))
1732 return mlir::failure();
1733 mlir::StringAttr linkAttr = builder.getStringAttr(linkage);
1734 result.addAttribute(fir::GlobalOp::getLinkNameAttrName(result.name),
1735 linkAttr);
1738 // Parse the name as a symbol reference attribute.
1739 mlir::SymbolRefAttr nameAttr;
1740 if (parser.parseAttribute(nameAttr,
1741 fir::GlobalOp::getSymrefAttrName(result.name),
1742 result.attributes))
1743 return mlir::failure();
1744 result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
1745 nameAttr.getRootReference());
1747 bool simpleInitializer = false;
1748 if (mlir::succeeded(parser.parseOptionalLParen())) {
1749 mlir::Attribute attr;
1750 if (parser.parseAttribute(attr, getInitValAttrName(result.name),
1751 result.attributes) ||
1752 parser.parseRParen())
1753 return mlir::failure();
1754 simpleInitializer = true;
1757 if (parser.parseOptionalAttrDict(result.attributes))
1758 return mlir::failure();
1760 if (succeeded(
1761 parser.parseOptionalKeyword(getConstantAttrName(result.name)))) {
1762 // if "constant" keyword then mark this as a constant, not a variable
1763 result.addAttribute(getConstantAttrName(result.name),
1764 builder.getUnitAttr());
1767 if (succeeded(parser.parseOptionalKeyword(getTargetAttrName(result.name))))
1768 result.addAttribute(getTargetAttrName(result.name), builder.getUnitAttr());
1770 mlir::Type globalType;
1771 if (parser.parseColonType(globalType))
1772 return mlir::failure();
1774 result.addAttribute(fir::GlobalOp::getTypeAttrName(result.name),
1775 mlir::TypeAttr::get(globalType));
1777 if (simpleInitializer) {
1778 result.addRegion();
1779 } else {
1780 // Parse the optional initializer body.
1781 auto parseResult =
1782 parser.parseOptionalRegion(*result.addRegion(), /*arguments=*/{});
1783 if (parseResult.has_value() && mlir::failed(*parseResult))
1784 return mlir::failure();
1786 return mlir::success();
1789 void fir::GlobalOp::print(mlir::OpAsmPrinter &p) {
1790 if (getLinkName())
1791 p << ' ' << *getLinkName();
1792 p << ' ';
1793 p.printAttributeWithoutType(getSymrefAttr());
1794 if (auto val = getValueOrNull())
1795 p << '(' << val << ')';
1796 // Print all other attributes that are not pretty printed here.
1797 p.printOptionalAttrDict((*this)->getAttrs(), /*elideAttrs=*/{
1798 getSymNameAttrName(), getSymrefAttrName(),
1799 getTypeAttrName(), getConstantAttrName(),
1800 getTargetAttrName(), getLinkNameAttrName(),
1801 getInitValAttrName()});
1802 if (getOperation()->getAttr(getConstantAttrName()))
1803 p << " " << getConstantAttrName().strref();
1804 if (getOperation()->getAttr(getTargetAttrName()))
1805 p << " " << getTargetAttrName().strref();
1806 p << " : ";
1807 p.printType(getType());
1808 if (hasInitializationBody()) {
1809 p << ' ';
1810 p.printRegion(getOperation()->getRegion(0),
1811 /*printEntryBlockArgs=*/false,
1812 /*printBlockTerminators=*/true);
1816 void fir::GlobalOp::appendInitialValue(mlir::Operation *op) {
1817 getBlock().getOperations().push_back(op);
1820 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1821 mlir::OperationState &result, llvm::StringRef name,
1822 bool isConstant, bool isTarget, mlir::Type type,
1823 mlir::Attribute initialVal, mlir::StringAttr linkage,
1824 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1825 result.addRegion();
1826 result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type));
1827 result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
1828 builder.getStringAttr(name));
1829 result.addAttribute(getSymrefAttrName(result.name),
1830 mlir::SymbolRefAttr::get(builder.getContext(), name));
1831 if (isConstant)
1832 result.addAttribute(getConstantAttrName(result.name),
1833 builder.getUnitAttr());
1834 if (isTarget)
1835 result.addAttribute(getTargetAttrName(result.name), builder.getUnitAttr());
1836 if (initialVal)
1837 result.addAttribute(getInitValAttrName(result.name), initialVal);
1838 if (linkage)
1839 result.addAttribute(getLinkNameAttrName(result.name), linkage);
1840 result.attributes.append(attrs.begin(), attrs.end());
1843 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1844 mlir::OperationState &result, llvm::StringRef name,
1845 mlir::Type type, mlir::Attribute initialVal,
1846 mlir::StringAttr linkage,
1847 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1848 build(builder, result, name, /*isConstant=*/false, /*isTarget=*/false, type,
1849 {}, linkage, attrs);
1852 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1853 mlir::OperationState &result, llvm::StringRef name,
1854 bool isConstant, bool isTarget, mlir::Type type,
1855 mlir::StringAttr linkage,
1856 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1857 build(builder, result, name, isConstant, isTarget, type, {}, linkage, attrs);
1860 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1861 mlir::OperationState &result, llvm::StringRef name,
1862 mlir::Type type, mlir::StringAttr linkage,
1863 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1864 build(builder, result, name, /*isConstant=*/false, /*isTarget=*/false, type,
1865 {}, linkage, attrs);
1868 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1869 mlir::OperationState &result, llvm::StringRef name,
1870 bool isConstant, bool isTarget, mlir::Type type,
1871 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1872 build(builder, result, name, isConstant, isTarget, type, mlir::StringAttr{},
1873 attrs);
1876 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1877 mlir::OperationState &result, llvm::StringRef name,
1878 mlir::Type type,
1879 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1880 build(builder, result, name, /*isConstant=*/false, /*isTarget=*/false, type,
1881 attrs);
1884 mlir::ParseResult fir::GlobalOp::verifyValidLinkage(llvm::StringRef linkage) {
1885 // Supporting only a subset of the LLVM linkage types for now
1886 static const char *validNames[] = {"common", "internal", "linkonce",
1887 "linkonce_odr", "weak"};
1888 return mlir::success(llvm::is_contained(validNames, linkage));
1891 //===----------------------------------------------------------------------===//
1892 // GlobalLenOp
1893 //===----------------------------------------------------------------------===//
1895 mlir::ParseResult fir::GlobalLenOp::parse(mlir::OpAsmParser &parser,
1896 mlir::OperationState &result) {
1897 llvm::StringRef fieldName;
1898 if (failed(parser.parseOptionalKeyword(&fieldName))) {
1899 mlir::StringAttr fieldAttr;
1900 if (parser.parseAttribute(fieldAttr,
1901 fir::GlobalLenOp::getLenParamAttrName(),
1902 result.attributes))
1903 return mlir::failure();
1904 } else {
1905 result.addAttribute(fir::GlobalLenOp::getLenParamAttrName(),
1906 parser.getBuilder().getStringAttr(fieldName));
1908 mlir::IntegerAttr constant;
1909 if (parser.parseComma() ||
1910 parser.parseAttribute(constant, fir::GlobalLenOp::getIntAttrName(),
1911 result.attributes))
1912 return mlir::failure();
1913 return mlir::success();
1916 void fir::GlobalLenOp::print(mlir::OpAsmPrinter &p) {
1917 p << ' ' << getOperation()->getAttr(fir::GlobalLenOp::getLenParamAttrName())
1918 << ", " << getOperation()->getAttr(fir::GlobalLenOp::getIntAttrName());
1921 //===----------------------------------------------------------------------===//
1922 // FieldIndexOp
1923 //===----------------------------------------------------------------------===//
1925 template <typename TY>
1926 mlir::ParseResult parseFieldLikeOp(mlir::OpAsmParser &parser,
1927 mlir::OperationState &result) {
1928 llvm::StringRef fieldName;
1929 auto &builder = parser.getBuilder();
1930 mlir::Type recty;
1931 if (parser.parseOptionalKeyword(&fieldName) || parser.parseComma() ||
1932 parser.parseType(recty))
1933 return mlir::failure();
1934 result.addAttribute(fir::FieldIndexOp::getFieldAttrName(),
1935 builder.getStringAttr(fieldName));
1936 if (!mlir::dyn_cast<fir::RecordType>(recty))
1937 return mlir::failure();
1938 result.addAttribute(fir::FieldIndexOp::getTypeAttrName(),
1939 mlir::TypeAttr::get(recty));
1940 if (!parser.parseOptionalLParen()) {
1941 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
1942 llvm::SmallVector<mlir::Type> types;
1943 auto loc = parser.getNameLoc();
1944 if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None) ||
1945 parser.parseColonTypeList(types) || parser.parseRParen() ||
1946 parser.resolveOperands(operands, types, loc, result.operands))
1947 return mlir::failure();
1949 mlir::Type fieldType = TY::get(builder.getContext());
1950 if (parser.addTypeToList(fieldType, result.types))
1951 return mlir::failure();
1952 return mlir::success();
1955 mlir::ParseResult fir::FieldIndexOp::parse(mlir::OpAsmParser &parser,
1956 mlir::OperationState &result) {
1957 return parseFieldLikeOp<fir::FieldType>(parser, result);
1960 template <typename OP>
1961 void printFieldLikeOp(mlir::OpAsmPrinter &p, OP &op) {
1962 p << ' '
1963 << op.getOperation()
1964 ->template getAttrOfType<mlir::StringAttr>(
1965 fir::FieldIndexOp::getFieldAttrName())
1966 .getValue()
1967 << ", " << op.getOperation()->getAttr(fir::FieldIndexOp::getTypeAttrName());
1968 if (op.getNumOperands()) {
1969 p << '(';
1970 p.printOperands(op.getTypeparams());
1971 auto sep = ") : ";
1972 for (auto op : op.getTypeparams()) {
1973 p << sep;
1974 if (op)
1975 p.printType(op.getType());
1976 else
1977 p << "()";
1978 sep = ", ";
1983 void fir::FieldIndexOp::print(mlir::OpAsmPrinter &p) {
1984 printFieldLikeOp(p, *this);
1987 void fir::FieldIndexOp::build(mlir::OpBuilder &builder,
1988 mlir::OperationState &result,
1989 llvm::StringRef fieldName, mlir::Type recTy,
1990 mlir::ValueRange operands) {
1991 result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));
1992 result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));
1993 result.addOperands(operands);
1996 llvm::SmallVector<mlir::Attribute> fir::FieldIndexOp::getAttributes() {
1997 llvm::SmallVector<mlir::Attribute> attrs;
1998 attrs.push_back(getFieldIdAttr());
1999 attrs.push_back(getOnTypeAttr());
2000 return attrs;
2003 //===----------------------------------------------------------------------===//
2004 // InsertOnRangeOp
2005 //===----------------------------------------------------------------------===//
2007 static mlir::ParseResult
2008 parseCustomRangeSubscript(mlir::OpAsmParser &parser,
2009 mlir::DenseIntElementsAttr &coord) {
2010 llvm::SmallVector<std::int64_t> lbounds;
2011 llvm::SmallVector<std::int64_t> ubounds;
2012 if (parser.parseKeyword("from") ||
2013 parser.parseCommaSeparatedList(
2014 mlir::AsmParser::Delimiter::Paren,
2015 [&] { return parser.parseInteger(lbounds.emplace_back(0)); }) ||
2016 parser.parseKeyword("to") ||
2017 parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::Paren, [&] {
2018 return parser.parseInteger(ubounds.emplace_back(0));
2020 return mlir::failure();
2021 llvm::SmallVector<std::int64_t> zippedBounds;
2022 for (auto zip : llvm::zip(lbounds, ubounds)) {
2023 zippedBounds.push_back(std::get<0>(zip));
2024 zippedBounds.push_back(std::get<1>(zip));
2026 coord = mlir::Builder(parser.getContext()).getIndexTensorAttr(zippedBounds);
2027 return mlir::success();
2030 static void printCustomRangeSubscript(mlir::OpAsmPrinter &printer,
2031 fir::InsertOnRangeOp op,
2032 mlir::DenseIntElementsAttr coord) {
2033 printer << "from (";
2034 auto enumerate = llvm::enumerate(coord.getValues<std::int64_t>());
2035 // Even entries are the lower bounds.
2036 llvm::interleaveComma(
2037 make_filter_range(
2038 enumerate,
2039 [](auto indexed_value) { return indexed_value.index() % 2 == 0; }),
2040 printer, [&](auto indexed_value) { printer << indexed_value.value(); });
2041 printer << ") to (";
2042 // Odd entries are the upper bounds.
2043 llvm::interleaveComma(
2044 make_filter_range(
2045 enumerate,
2046 [](auto indexed_value) { return indexed_value.index() % 2 != 0; }),
2047 printer, [&](auto indexed_value) { printer << indexed_value.value(); });
2048 printer << ")";
2051 /// Range bounds must be nonnegative, and the range must not be empty.
2052 llvm::LogicalResult fir::InsertOnRangeOp::verify() {
2053 if (fir::hasDynamicSize(getSeq().getType()))
2054 return emitOpError("must have constant shape and size");
2055 mlir::DenseIntElementsAttr coorAttr = getCoor();
2056 if (coorAttr.size() < 2 || coorAttr.size() % 2 != 0)
2057 return emitOpError("has uneven number of values in ranges");
2058 bool rangeIsKnownToBeNonempty = false;
2059 for (auto i = coorAttr.getValues<std::int64_t>().end(),
2060 b = coorAttr.getValues<std::int64_t>().begin();
2061 i != b;) {
2062 int64_t ub = (*--i);
2063 int64_t lb = (*--i);
2064 if (lb < 0 || ub < 0)
2065 return emitOpError("negative range bound");
2066 if (rangeIsKnownToBeNonempty)
2067 continue;
2068 if (lb > ub)
2069 return emitOpError("empty range");
2070 rangeIsKnownToBeNonempty = lb < ub;
2072 return mlir::success();
2075 //===----------------------------------------------------------------------===//
2076 // InsertValueOp
2077 //===----------------------------------------------------------------------===//
2079 static bool checkIsIntegerConstant(mlir::Attribute attr, std::int64_t conVal) {
2080 if (auto iattr = mlir::dyn_cast<mlir::IntegerAttr>(attr))
2081 return iattr.getInt() == conVal;
2082 return false;
2085 static bool isZero(mlir::Attribute a) { return checkIsIntegerConstant(a, 0); }
2086 static bool isOne(mlir::Attribute a) { return checkIsIntegerConstant(a, 1); }
2088 // Undo some complex patterns created in the front-end and turn them back into
2089 // complex ops.
2090 template <typename FltOp, typename CpxOp>
2091 struct UndoComplexPattern : public mlir::RewritePattern {
2092 UndoComplexPattern(mlir::MLIRContext *ctx)
2093 : mlir::RewritePattern("fir.insert_value", 2, ctx) {}
2095 llvm::LogicalResult
2096 matchAndRewrite(mlir::Operation *op,
2097 mlir::PatternRewriter &rewriter) const override {
2098 auto insval = mlir::dyn_cast_or_null<fir::InsertValueOp>(op);
2099 if (!insval || !mlir::isa<mlir::ComplexType>(insval.getType()))
2100 return mlir::failure();
2101 auto insval2 = mlir::dyn_cast_or_null<fir::InsertValueOp>(
2102 insval.getAdt().getDefiningOp());
2103 if (!insval2)
2104 return mlir::failure();
2105 auto binf = mlir::dyn_cast_or_null<FltOp>(insval.getVal().getDefiningOp());
2106 auto binf2 =
2107 mlir::dyn_cast_or_null<FltOp>(insval2.getVal().getDefiningOp());
2108 if (!binf || !binf2 || insval.getCoor().size() != 1 ||
2109 !isOne(insval.getCoor()[0]) || insval2.getCoor().size() != 1 ||
2110 !isZero(insval2.getCoor()[0]))
2111 return mlir::failure();
2112 auto eai = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
2113 binf.getLhs().getDefiningOp());
2114 auto ebi = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
2115 binf.getRhs().getDefiningOp());
2116 auto ear = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
2117 binf2.getLhs().getDefiningOp());
2118 auto ebr = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
2119 binf2.getRhs().getDefiningOp());
2120 if (!eai || !ebi || !ear || !ebr || ear.getAdt() != eai.getAdt() ||
2121 ebr.getAdt() != ebi.getAdt() || eai.getCoor().size() != 1 ||
2122 !isOne(eai.getCoor()[0]) || ebi.getCoor().size() != 1 ||
2123 !isOne(ebi.getCoor()[0]) || ear.getCoor().size() != 1 ||
2124 !isZero(ear.getCoor()[0]) || ebr.getCoor().size() != 1 ||
2125 !isZero(ebr.getCoor()[0]))
2126 return mlir::failure();
2127 rewriter.replaceOpWithNewOp<CpxOp>(op, ear.getAdt(), ebr.getAdt());
2128 return mlir::success();
2132 void fir::InsertValueOp::getCanonicalizationPatterns(
2133 mlir::RewritePatternSet &results, mlir::MLIRContext *context) {
2134 results.insert<UndoComplexPattern<mlir::arith::AddFOp, fir::AddcOp>,
2135 UndoComplexPattern<mlir::arith::SubFOp, fir::SubcOp>>(context);
2138 //===----------------------------------------------------------------------===//
2139 // IterWhileOp
2140 //===----------------------------------------------------------------------===//
2142 void fir::IterWhileOp::build(mlir::OpBuilder &builder,
2143 mlir::OperationState &result, mlir::Value lb,
2144 mlir::Value ub, mlir::Value step,
2145 mlir::Value iterate, bool finalCountValue,
2146 mlir::ValueRange iterArgs,
2147 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
2148 result.addOperands({lb, ub, step, iterate});
2149 if (finalCountValue) {
2150 result.addTypes(builder.getIndexType());
2151 result.addAttribute(getFinalValueAttrNameStr(), builder.getUnitAttr());
2153 result.addTypes(iterate.getType());
2154 result.addOperands(iterArgs);
2155 for (auto v : iterArgs)
2156 result.addTypes(v.getType());
2157 mlir::Region *bodyRegion = result.addRegion();
2158 bodyRegion->push_back(new mlir::Block{});
2159 bodyRegion->front().addArgument(builder.getIndexType(), result.location);
2160 bodyRegion->front().addArgument(iterate.getType(), result.location);
2161 bodyRegion->front().addArguments(
2162 iterArgs.getTypes(),
2163 llvm::SmallVector<mlir::Location>(iterArgs.size(), result.location));
2164 result.addAttributes(attributes);
2167 mlir::ParseResult fir::IterWhileOp::parse(mlir::OpAsmParser &parser,
2168 mlir::OperationState &result) {
2169 auto &builder = parser.getBuilder();
2170 mlir::OpAsmParser::Argument inductionVariable, iterateVar;
2171 mlir::OpAsmParser::UnresolvedOperand lb, ub, step, iterateInput;
2172 if (parser.parseLParen() || parser.parseArgument(inductionVariable) ||
2173 parser.parseEqual())
2174 return mlir::failure();
2176 // Parse loop bounds.
2177 auto indexType = builder.getIndexType();
2178 auto i1Type = builder.getIntegerType(1);
2179 if (parser.parseOperand(lb) ||
2180 parser.resolveOperand(lb, indexType, result.operands) ||
2181 parser.parseKeyword("to") || parser.parseOperand(ub) ||
2182 parser.resolveOperand(ub, indexType, result.operands) ||
2183 parser.parseKeyword("step") || parser.parseOperand(step) ||
2184 parser.parseRParen() ||
2185 parser.resolveOperand(step, indexType, result.operands) ||
2186 parser.parseKeyword("and") || parser.parseLParen() ||
2187 parser.parseArgument(iterateVar) || parser.parseEqual() ||
2188 parser.parseOperand(iterateInput) || parser.parseRParen() ||
2189 parser.resolveOperand(iterateInput, i1Type, result.operands))
2190 return mlir::failure();
2192 // Parse the initial iteration arguments.
2193 auto prependCount = false;
2195 // Induction variable.
2196 llvm::SmallVector<mlir::OpAsmParser::Argument> regionArgs;
2197 regionArgs.push_back(inductionVariable);
2198 regionArgs.push_back(iterateVar);
2200 if (succeeded(parser.parseOptionalKeyword("iter_args"))) {
2201 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
2202 llvm::SmallVector<mlir::Type> regionTypes;
2203 // Parse assignment list and results type list.
2204 if (parser.parseAssignmentList(regionArgs, operands) ||
2205 parser.parseArrowTypeList(regionTypes))
2206 return mlir::failure();
2207 if (regionTypes.size() == operands.size() + 2)
2208 prependCount = true;
2209 llvm::ArrayRef<mlir::Type> resTypes = regionTypes;
2210 resTypes = prependCount ? resTypes.drop_front(2) : resTypes;
2211 // Resolve input operands.
2212 for (auto operandType : llvm::zip(operands, resTypes))
2213 if (parser.resolveOperand(std::get<0>(operandType),
2214 std::get<1>(operandType), result.operands))
2215 return mlir::failure();
2216 if (prependCount) {
2217 result.addTypes(regionTypes);
2218 } else {
2219 result.addTypes(i1Type);
2220 result.addTypes(resTypes);
2222 } else if (succeeded(parser.parseOptionalArrow())) {
2223 llvm::SmallVector<mlir::Type> typeList;
2224 if (parser.parseLParen() || parser.parseTypeList(typeList) ||
2225 parser.parseRParen())
2226 return mlir::failure();
2227 // Type list must be "(index, i1)".
2228 if (typeList.size() != 2 || !mlir::isa<mlir::IndexType>(typeList[0]) ||
2229 !typeList[1].isSignlessInteger(1))
2230 return mlir::failure();
2231 result.addTypes(typeList);
2232 prependCount = true;
2233 } else {
2234 result.addTypes(i1Type);
2237 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2238 return mlir::failure();
2240 llvm::SmallVector<mlir::Type> argTypes;
2241 // Induction variable (hidden)
2242 if (prependCount)
2243 result.addAttribute(IterWhileOp::getFinalValueAttrNameStr(),
2244 builder.getUnitAttr());
2245 else
2246 argTypes.push_back(indexType);
2247 // Loop carried variables (including iterate)
2248 argTypes.append(result.types.begin(), result.types.end());
2249 // Parse the body region.
2250 auto *body = result.addRegion();
2251 if (regionArgs.size() != argTypes.size())
2252 return parser.emitError(
2253 parser.getNameLoc(),
2254 "mismatch in number of loop-carried values and defined values");
2256 for (size_t i = 0, e = regionArgs.size(); i != e; ++i)
2257 regionArgs[i].type = argTypes[i];
2259 if (parser.parseRegion(*body, regionArgs))
2260 return mlir::failure();
2262 fir::IterWhileOp::ensureTerminator(*body, builder, result.location);
2263 return mlir::success();
2266 llvm::LogicalResult fir::IterWhileOp::verify() {
2267 // Check that the body defines as single block argument for the induction
2268 // variable.
2269 auto *body = getBody();
2270 if (!body->getArgument(1).getType().isInteger(1))
2271 return emitOpError(
2272 "expected body second argument to be an index argument for "
2273 "the induction variable");
2274 if (!body->getArgument(0).getType().isIndex())
2275 return emitOpError(
2276 "expected body first argument to be an index argument for "
2277 "the induction variable");
2279 auto opNumResults = getNumResults();
2280 if (getFinalValue()) {
2281 // Result type must be "(index, i1, ...)".
2282 if (!mlir::isa<mlir::IndexType>(getResult(0).getType()))
2283 return emitOpError("result #0 expected to be index");
2284 if (!getResult(1).getType().isSignlessInteger(1))
2285 return emitOpError("result #1 expected to be i1");
2286 opNumResults--;
2287 } else {
2288 // iterate_while always returns the early exit induction value.
2289 // Result type must be "(i1, ...)"
2290 if (!getResult(0).getType().isSignlessInteger(1))
2291 return emitOpError("result #0 expected to be i1");
2293 if (opNumResults == 0)
2294 return mlir::failure();
2295 if (getNumIterOperands() != opNumResults)
2296 return emitOpError(
2297 "mismatch in number of loop-carried values and defined values");
2298 if (getNumRegionIterArgs() != opNumResults)
2299 return emitOpError(
2300 "mismatch in number of basic block args and defined values");
2301 auto iterOperands = getIterOperands();
2302 auto iterArgs = getRegionIterArgs();
2303 auto opResults = getFinalValue() ? getResults().drop_front() : getResults();
2304 unsigned i = 0u;
2305 for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {
2306 if (std::get<0>(e).getType() != std::get<2>(e).getType())
2307 return emitOpError() << "types mismatch between " << i
2308 << "th iter operand and defined value";
2309 if (std::get<1>(e).getType() != std::get<2>(e).getType())
2310 return emitOpError() << "types mismatch between " << i
2311 << "th iter region arg and defined value";
2313 i++;
2315 return mlir::success();
2318 void fir::IterWhileOp::print(mlir::OpAsmPrinter &p) {
2319 p << " (" << getInductionVar() << " = " << getLowerBound() << " to "
2320 << getUpperBound() << " step " << getStep() << ") and (";
2321 assert(hasIterOperands());
2322 auto regionArgs = getRegionIterArgs();
2323 auto operands = getIterOperands();
2324 p << regionArgs.front() << " = " << *operands.begin() << ")";
2325 if (regionArgs.size() > 1) {
2326 p << " iter_args(";
2327 llvm::interleaveComma(
2328 llvm::zip(regionArgs.drop_front(), operands.drop_front()), p,
2329 [&](auto it) { p << std::get<0>(it) << " = " << std::get<1>(it); });
2330 p << ") -> (";
2331 llvm::interleaveComma(
2332 llvm::drop_begin(getResultTypes(), getFinalValue() ? 0 : 1), p);
2333 p << ")";
2334 } else if (getFinalValue()) {
2335 p << " -> (" << getResultTypes() << ')';
2337 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(),
2338 {getFinalValueAttrNameStr()});
2339 p << ' ';
2340 p.printRegion(getRegion(), /*printEntryBlockArgs=*/false,
2341 /*printBlockTerminators=*/true);
2344 llvm::SmallVector<mlir::Region *> fir::IterWhileOp::getLoopRegions() {
2345 return {&getRegion()};
2348 mlir::BlockArgument fir::IterWhileOp::iterArgToBlockArg(mlir::Value iterArg) {
2349 for (auto i : llvm::enumerate(getInitArgs()))
2350 if (iterArg == i.value())
2351 return getRegion().front().getArgument(i.index() + 1);
2352 return {};
2355 void fir::IterWhileOp::resultToSourceOps(
2356 llvm::SmallVectorImpl<mlir::Value> &results, unsigned resultNum) {
2357 auto oper = getFinalValue() ? resultNum + 1 : resultNum;
2358 auto *term = getRegion().front().getTerminator();
2359 if (oper < term->getNumOperands())
2360 results.push_back(term->getOperand(oper));
2363 mlir::Value fir::IterWhileOp::blockArgToSourceOp(unsigned blockArgNum) {
2364 if (blockArgNum > 0 && blockArgNum <= getInitArgs().size())
2365 return getInitArgs()[blockArgNum - 1];
2366 return {};
2369 std::optional<llvm::MutableArrayRef<mlir::OpOperand>>
2370 fir::IterWhileOp::getYieldedValuesMutable() {
2371 auto *term = getRegion().front().getTerminator();
2372 return getFinalValue() ? term->getOpOperands().drop_front()
2373 : term->getOpOperands();
2376 //===----------------------------------------------------------------------===//
2377 // LenParamIndexOp
2378 //===----------------------------------------------------------------------===//
2380 mlir::ParseResult fir::LenParamIndexOp::parse(mlir::OpAsmParser &parser,
2381 mlir::OperationState &result) {
2382 return parseFieldLikeOp<fir::LenType>(parser, result);
2385 void fir::LenParamIndexOp::print(mlir::OpAsmPrinter &p) {
2386 printFieldLikeOp(p, *this);
2389 void fir::LenParamIndexOp::build(mlir::OpBuilder &builder,
2390 mlir::OperationState &result,
2391 llvm::StringRef fieldName, mlir::Type recTy,
2392 mlir::ValueRange operands) {
2393 result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));
2394 result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));
2395 result.addOperands(operands);
2398 llvm::SmallVector<mlir::Attribute> fir::LenParamIndexOp::getAttributes() {
2399 llvm::SmallVector<mlir::Attribute> attrs;
2400 attrs.push_back(getFieldIdAttr());
2401 attrs.push_back(getOnTypeAttr());
2402 return attrs;
2405 //===----------------------------------------------------------------------===//
2406 // LoadOp
2407 //===----------------------------------------------------------------------===//
2409 void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
2410 mlir::Value refVal) {
2411 if (!refVal) {
2412 mlir::emitError(result.location, "LoadOp has null argument");
2413 return;
2415 auto eleTy = fir::dyn_cast_ptrEleTy(refVal.getType());
2416 if (!eleTy) {
2417 mlir::emitError(result.location, "not a memory reference type");
2418 return;
2420 build(builder, result, eleTy, refVal);
2423 void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
2424 mlir::Type resTy, mlir::Value refVal) {
2426 if (!refVal) {
2427 mlir::emitError(result.location, "LoadOp has null argument");
2428 return;
2430 result.addOperands(refVal);
2431 result.addTypes(resTy);
2434 mlir::ParseResult fir::LoadOp::getElementOf(mlir::Type &ele, mlir::Type ref) {
2435 if ((ele = fir::dyn_cast_ptrEleTy(ref)))
2436 return mlir::success();
2437 return mlir::failure();
2440 mlir::ParseResult fir::LoadOp::parse(mlir::OpAsmParser &parser,
2441 mlir::OperationState &result) {
2442 mlir::Type type;
2443 mlir::OpAsmParser::UnresolvedOperand oper;
2444 if (parser.parseOperand(oper) ||
2445 parser.parseOptionalAttrDict(result.attributes) ||
2446 parser.parseColonType(type) ||
2447 parser.resolveOperand(oper, type, result.operands))
2448 return mlir::failure();
2449 mlir::Type eleTy;
2450 if (fir::LoadOp::getElementOf(eleTy, type) ||
2451 parser.addTypeToList(eleTy, result.types))
2452 return mlir::failure();
2453 return mlir::success();
2456 void fir::LoadOp::print(mlir::OpAsmPrinter &p) {
2457 p << ' ';
2458 p.printOperand(getMemref());
2459 p.printOptionalAttrDict(getOperation()->getAttrs(), {});
2460 p << " : " << getMemref().getType();
2463 //===----------------------------------------------------------------------===//
2464 // DoLoopOp
2465 //===----------------------------------------------------------------------===//
2467 void fir::DoLoopOp::build(mlir::OpBuilder &builder,
2468 mlir::OperationState &result, mlir::Value lb,
2469 mlir::Value ub, mlir::Value step, bool unordered,
2470 bool finalCountValue, mlir::ValueRange iterArgs,
2471 mlir::ValueRange reduceOperands,
2472 llvm::ArrayRef<mlir::Attribute> reduceAttrs,
2473 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
2474 result.addOperands({lb, ub, step});
2475 result.addOperands(reduceOperands);
2476 result.addOperands(iterArgs);
2477 result.addAttribute(getOperandSegmentSizeAttr(),
2478 builder.getDenseI32ArrayAttr(
2479 {1, 1, 1, static_cast<int32_t>(reduceOperands.size()),
2480 static_cast<int32_t>(iterArgs.size())}));
2481 if (finalCountValue) {
2482 result.addTypes(builder.getIndexType());
2483 result.addAttribute(getFinalValueAttrName(result.name),
2484 builder.getUnitAttr());
2486 for (auto v : iterArgs)
2487 result.addTypes(v.getType());
2488 mlir::Region *bodyRegion = result.addRegion();
2489 bodyRegion->push_back(new mlir::Block{});
2490 if (iterArgs.empty() && !finalCountValue)
2491 fir::DoLoopOp::ensureTerminator(*bodyRegion, builder, result.location);
2492 bodyRegion->front().addArgument(builder.getIndexType(), result.location);
2493 bodyRegion->front().addArguments(
2494 iterArgs.getTypes(),
2495 llvm::SmallVector<mlir::Location>(iterArgs.size(), result.location));
2496 if (unordered)
2497 result.addAttribute(getUnorderedAttrName(result.name),
2498 builder.getUnitAttr());
2499 if (!reduceAttrs.empty())
2500 result.addAttribute(getReduceAttrsAttrName(result.name),
2501 builder.getArrayAttr(reduceAttrs));
2502 result.addAttributes(attributes);
2505 mlir::ParseResult fir::DoLoopOp::parse(mlir::OpAsmParser &parser,
2506 mlir::OperationState &result) {
2507 auto &builder = parser.getBuilder();
2508 mlir::OpAsmParser::Argument inductionVariable;
2509 mlir::OpAsmParser::UnresolvedOperand lb, ub, step;
2510 // Parse the induction variable followed by '='.
2511 if (parser.parseArgument(inductionVariable) || parser.parseEqual())
2512 return mlir::failure();
2514 // Parse loop bounds.
2515 auto indexType = builder.getIndexType();
2516 if (parser.parseOperand(lb) ||
2517 parser.resolveOperand(lb, indexType, result.operands) ||
2518 parser.parseKeyword("to") || parser.parseOperand(ub) ||
2519 parser.resolveOperand(ub, indexType, result.operands) ||
2520 parser.parseKeyword("step") || parser.parseOperand(step) ||
2521 parser.resolveOperand(step, indexType, result.operands))
2522 return mlir::failure();
2524 if (mlir::succeeded(parser.parseOptionalKeyword("unordered")))
2525 result.addAttribute("unordered", builder.getUnitAttr());
2527 // Parse the reduction arguments.
2528 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> reduceOperands;
2529 llvm::SmallVector<mlir::Type> reduceArgTypes;
2530 if (succeeded(parser.parseOptionalKeyword("reduce"))) {
2531 // Parse reduction attributes and variables.
2532 llvm::SmallVector<ReduceAttr> attributes;
2533 if (failed(parser.parseCommaSeparatedList(
2534 mlir::AsmParser::Delimiter::Paren, [&]() {
2535 if (parser.parseAttribute(attributes.emplace_back()) ||
2536 parser.parseArrow() ||
2537 parser.parseOperand(reduceOperands.emplace_back()) ||
2538 parser.parseColonType(reduceArgTypes.emplace_back()))
2539 return mlir::failure();
2540 return mlir::success();
2541 })))
2542 return mlir::failure();
2543 // Resolve input operands.
2544 for (auto operand_type : llvm::zip(reduceOperands, reduceArgTypes))
2545 if (parser.resolveOperand(std::get<0>(operand_type),
2546 std::get<1>(operand_type), result.operands))
2547 return mlir::failure();
2548 llvm::SmallVector<mlir::Attribute> arrayAttr(attributes.begin(),
2549 attributes.end());
2550 result.addAttribute(getReduceAttrsAttrName(result.name),
2551 builder.getArrayAttr(arrayAttr));
2554 // Parse the optional initial iteration arguments.
2555 llvm::SmallVector<mlir::OpAsmParser::Argument> regionArgs;
2556 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> iterOperands;
2557 llvm::SmallVector<mlir::Type> argTypes;
2558 bool prependCount = false;
2559 regionArgs.push_back(inductionVariable);
2561 if (succeeded(parser.parseOptionalKeyword("iter_args"))) {
2562 // Parse assignment list and results type list.
2563 if (parser.parseAssignmentList(regionArgs, iterOperands) ||
2564 parser.parseArrowTypeList(result.types))
2565 return mlir::failure();
2566 if (result.types.size() == iterOperands.size() + 1)
2567 prependCount = true;
2568 // Resolve input operands.
2569 llvm::ArrayRef<mlir::Type> resTypes = result.types;
2570 for (auto operand_type : llvm::zip(
2571 iterOperands, prependCount ? resTypes.drop_front() : resTypes))
2572 if (parser.resolveOperand(std::get<0>(operand_type),
2573 std::get<1>(operand_type), result.operands))
2574 return mlir::failure();
2575 } else if (succeeded(parser.parseOptionalArrow())) {
2576 if (parser.parseKeyword("index"))
2577 return mlir::failure();
2578 result.types.push_back(indexType);
2579 prependCount = true;
2582 // Set the operandSegmentSizes attribute
2583 result.addAttribute(getOperandSegmentSizeAttr(),
2584 builder.getDenseI32ArrayAttr(
2585 {1, 1, 1, static_cast<int32_t>(reduceOperands.size()),
2586 static_cast<int32_t>(iterOperands.size())}));
2588 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2589 return mlir::failure();
2591 // Induction variable.
2592 if (prependCount)
2593 result.addAttribute(DoLoopOp::getFinalValueAttrName(result.name),
2594 builder.getUnitAttr());
2595 else
2596 argTypes.push_back(indexType);
2597 // Loop carried variables
2598 argTypes.append(result.types.begin(), result.types.end());
2599 // Parse the body region.
2600 auto *body = result.addRegion();
2601 if (regionArgs.size() != argTypes.size())
2602 return parser.emitError(
2603 parser.getNameLoc(),
2604 "mismatch in number of loop-carried values and defined values");
2605 for (size_t i = 0, e = regionArgs.size(); i != e; ++i)
2606 regionArgs[i].type = argTypes[i];
2608 if (parser.parseRegion(*body, regionArgs))
2609 return mlir::failure();
2611 DoLoopOp::ensureTerminator(*body, builder, result.location);
2613 return mlir::success();
2616 fir::DoLoopOp fir::getForInductionVarOwner(mlir::Value val) {
2617 auto ivArg = mlir::dyn_cast<mlir::BlockArgument>(val);
2618 if (!ivArg)
2619 return {};
2620 assert(ivArg.getOwner() && "unlinked block argument");
2621 auto *containingInst = ivArg.getOwner()->getParentOp();
2622 return mlir::dyn_cast_or_null<fir::DoLoopOp>(containingInst);
2625 // Lifted from loop.loop
2626 llvm::LogicalResult fir::DoLoopOp::verify() {
2627 // Check that the body defines as single block argument for the induction
2628 // variable.
2629 auto *body = getBody();
2630 if (!body->getArgument(0).getType().isIndex())
2631 return emitOpError(
2632 "expected body first argument to be an index argument for "
2633 "the induction variable");
2635 auto opNumResults = getNumResults();
2636 if (opNumResults == 0)
2637 return mlir::success();
2639 if (getFinalValue()) {
2640 if (getUnordered())
2641 return emitOpError("unordered loop has no final value");
2642 opNumResults--;
2644 if (getNumIterOperands() != opNumResults)
2645 return emitOpError(
2646 "mismatch in number of loop-carried values and defined values");
2647 if (getNumRegionIterArgs() != opNumResults)
2648 return emitOpError(
2649 "mismatch in number of basic block args and defined values");
2650 auto iterOperands = getIterOperands();
2651 auto iterArgs = getRegionIterArgs();
2652 auto opResults = getFinalValue() ? getResults().drop_front() : getResults();
2653 unsigned i = 0u;
2654 for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {
2655 if (std::get<0>(e).getType() != std::get<2>(e).getType())
2656 return emitOpError() << "types mismatch between " << i
2657 << "th iter operand and defined value";
2658 if (std::get<1>(e).getType() != std::get<2>(e).getType())
2659 return emitOpError() << "types mismatch between " << i
2660 << "th iter region arg and defined value";
2662 i++;
2664 auto reduceAttrs = getReduceAttrsAttr();
2665 if (getNumReduceOperands() != (reduceAttrs ? reduceAttrs.size() : 0))
2666 return emitOpError(
2667 "mismatch in number of reduction variables and reduction attributes");
2668 return mlir::success();
2671 void fir::DoLoopOp::print(mlir::OpAsmPrinter &p) {
2672 bool printBlockTerminators = false;
2673 p << ' ' << getInductionVar() << " = " << getLowerBound() << " to "
2674 << getUpperBound() << " step " << getStep();
2675 if (getUnordered())
2676 p << " unordered";
2677 if (hasReduceOperands()) {
2678 p << " reduce(";
2679 auto attrs = getReduceAttrsAttr();
2680 auto operands = getReduceOperands();
2681 llvm::interleaveComma(llvm::zip(attrs, operands), p, [&](auto it) {
2682 p << std::get<0>(it) << " -> " << std::get<1>(it) << " : "
2683 << std::get<1>(it).getType();
2685 p << ')';
2686 printBlockTerminators = true;
2688 if (hasIterOperands()) {
2689 p << " iter_args(";
2690 auto regionArgs = getRegionIterArgs();
2691 auto operands = getIterOperands();
2692 llvm::interleaveComma(llvm::zip(regionArgs, operands), p, [&](auto it) {
2693 p << std::get<0>(it) << " = " << std::get<1>(it);
2695 p << ") -> (" << getResultTypes() << ')';
2696 printBlockTerminators = true;
2697 } else if (getFinalValue()) {
2698 p << " -> " << getResultTypes();
2699 printBlockTerminators = true;
2701 p.printOptionalAttrDictWithKeyword(
2702 (*this)->getAttrs(),
2703 {"unordered", "finalValue", "reduceAttrs", "operandSegmentSizes"});
2704 p << ' ';
2705 p.printRegion(getRegion(), /*printEntryBlockArgs=*/false,
2706 printBlockTerminators);
2709 llvm::SmallVector<mlir::Region *> fir::DoLoopOp::getLoopRegions() {
2710 return {&getRegion()};
2713 /// Translate a value passed as an iter_arg to the corresponding block
2714 /// argument in the body of the loop.
2715 mlir::BlockArgument fir::DoLoopOp::iterArgToBlockArg(mlir::Value iterArg) {
2716 for (auto i : llvm::enumerate(getInitArgs()))
2717 if (iterArg == i.value())
2718 return getRegion().front().getArgument(i.index() + 1);
2719 return {};
2722 /// Translate the result vector (by index number) to the corresponding value
2723 /// to the `fir.result` Op.
2724 void fir::DoLoopOp::resultToSourceOps(
2725 llvm::SmallVectorImpl<mlir::Value> &results, unsigned resultNum) {
2726 auto oper = getFinalValue() ? resultNum + 1 : resultNum;
2727 auto *term = getRegion().front().getTerminator();
2728 if (oper < term->getNumOperands())
2729 results.push_back(term->getOperand(oper));
2732 /// Translate the block argument (by index number) to the corresponding value
2733 /// passed as an iter_arg to the parent DoLoopOp.
2734 mlir::Value fir::DoLoopOp::blockArgToSourceOp(unsigned blockArgNum) {
2735 if (blockArgNum > 0 && blockArgNum <= getInitArgs().size())
2736 return getInitArgs()[blockArgNum - 1];
2737 return {};
2740 std::optional<llvm::MutableArrayRef<mlir::OpOperand>>
2741 fir::DoLoopOp::getYieldedValuesMutable() {
2742 auto *term = getRegion().front().getTerminator();
2743 return getFinalValue() ? term->getOpOperands().drop_front()
2744 : term->getOpOperands();
2747 //===----------------------------------------------------------------------===//
2748 // DTEntryOp
2749 //===----------------------------------------------------------------------===//
2751 mlir::ParseResult fir::DTEntryOp::parse(mlir::OpAsmParser &parser,
2752 mlir::OperationState &result) {
2753 llvm::StringRef methodName;
2754 // allow `methodName` or `"methodName"`
2755 if (failed(parser.parseOptionalKeyword(&methodName))) {
2756 mlir::StringAttr methodAttr;
2757 if (parser.parseAttribute(methodAttr, getMethodAttrName(result.name),
2758 result.attributes))
2759 return mlir::failure();
2760 } else {
2761 result.addAttribute(getMethodAttrName(result.name),
2762 parser.getBuilder().getStringAttr(methodName));
2764 mlir::SymbolRefAttr calleeAttr;
2765 if (parser.parseComma() ||
2766 parser.parseAttribute(calleeAttr, fir::DTEntryOp::getProcAttrNameStr(),
2767 result.attributes))
2768 return mlir::failure();
2769 return mlir::success();
2772 void fir::DTEntryOp::print(mlir::OpAsmPrinter &p) {
2773 p << ' ' << getMethodAttr() << ", " << getProcAttr();
2776 //===----------------------------------------------------------------------===//
2777 // ReboxOp
2778 //===----------------------------------------------------------------------===//
2780 /// Get the scalar type related to a fir.box type.
2781 /// Example: return f32 for !fir.box<!fir.heap<!fir.array<?x?xf32>>.
2782 static mlir::Type getBoxScalarEleTy(mlir::Type boxTy) {
2783 auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(boxTy);
2784 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy))
2785 return seqTy.getEleTy();
2786 return eleTy;
2789 /// Test if \p t1 and \p t2 are compatible character types (if they can
2790 /// represent the same type at runtime).
2791 static bool areCompatibleCharacterTypes(mlir::Type t1, mlir::Type t2) {
2792 auto c1 = mlir::dyn_cast<fir::CharacterType>(t1);
2793 auto c2 = mlir::dyn_cast<fir::CharacterType>(t2);
2794 if (!c1 || !c2)
2795 return false;
2796 if (c1.hasDynamicLen() || c2.hasDynamicLen())
2797 return true;
2798 return c1.getLen() == c2.getLen();
2801 llvm::LogicalResult fir::ReboxOp::verify() {
2802 auto inputBoxTy = getBox().getType();
2803 if (fir::isa_unknown_size_box(inputBoxTy))
2804 return emitOpError("box operand must not have unknown rank or type");
2805 auto outBoxTy = getType();
2806 if (fir::isa_unknown_size_box(outBoxTy))
2807 return emitOpError("result type must not have unknown rank or type");
2808 auto inputRank = fir::getBoxRank(inputBoxTy);
2809 auto inputEleTy = getBoxScalarEleTy(inputBoxTy);
2810 auto outRank = fir::getBoxRank(outBoxTy);
2811 auto outEleTy = getBoxScalarEleTy(outBoxTy);
2813 if (auto sliceVal = getSlice()) {
2814 // Slicing case
2815 if (mlir::cast<fir::SliceType>(sliceVal.getType()).getRank() != inputRank)
2816 return emitOpError("slice operand rank must match box operand rank");
2817 if (auto shapeVal = getShape()) {
2818 if (auto shiftTy = mlir::dyn_cast<fir::ShiftType>(shapeVal.getType())) {
2819 if (shiftTy.getRank() != inputRank)
2820 return emitOpError("shape operand and input box ranks must match "
2821 "when there is a slice");
2822 } else {
2823 return emitOpError("shape operand must absent or be a fir.shift "
2824 "when there is a slice");
2827 if (auto sliceOp = sliceVal.getDefiningOp()) {
2828 auto slicedRank = mlir::cast<fir::SliceOp>(sliceOp).getOutRank();
2829 if (slicedRank != outRank)
2830 return emitOpError("result type rank and rank after applying slice "
2831 "operand must match");
2833 } else {
2834 // Reshaping case
2835 unsigned shapeRank = inputRank;
2836 if (auto shapeVal = getShape()) {
2837 auto ty = shapeVal.getType();
2838 if (auto shapeTy = mlir::dyn_cast<fir::ShapeType>(ty)) {
2839 shapeRank = shapeTy.getRank();
2840 } else if (auto shapeShiftTy = mlir::dyn_cast<fir::ShapeShiftType>(ty)) {
2841 shapeRank = shapeShiftTy.getRank();
2842 } else {
2843 auto shiftTy = mlir::cast<fir::ShiftType>(ty);
2844 shapeRank = shiftTy.getRank();
2845 if (shapeRank != inputRank)
2846 return emitOpError("shape operand and input box ranks must match "
2847 "when the shape is a fir.shift");
2850 if (shapeRank != outRank)
2851 return emitOpError("result type and shape operand ranks must match");
2854 if (inputEleTy != outEleTy) {
2855 // TODO: check that outBoxTy is a parent type of inputBoxTy for derived
2856 // types.
2857 // Character input and output types with constant length may be different if
2858 // there is a substring in the slice, otherwise, they must match. If any of
2859 // the types is a character with dynamic length, the other type can be any
2860 // character type.
2861 const bool typeCanMismatch =
2862 mlir::isa<fir::RecordType>(inputEleTy) ||
2863 mlir::isa<mlir::NoneType>(outEleTy) ||
2864 (mlir::isa<mlir::NoneType>(inputEleTy) &&
2865 mlir::isa<fir::RecordType>(outEleTy)) ||
2866 (getSlice() && mlir::isa<fir::CharacterType>(inputEleTy)) ||
2867 (getSlice() && fir::isa_complex(inputEleTy) &&
2868 mlir::isa<mlir::FloatType>(outEleTy)) ||
2869 areCompatibleCharacterTypes(inputEleTy, outEleTy);
2870 if (!typeCanMismatch)
2871 return emitOpError(
2872 "op input and output element types must match for intrinsic types");
2874 return mlir::success();
2877 //===----------------------------------------------------------------------===//
2878 // ReboxAssumedRankOp
2879 //===----------------------------------------------------------------------===//
2881 static bool areCompatibleAssumedRankElementType(mlir::Type inputEleTy,
2882 mlir::Type outEleTy) {
2883 if (inputEleTy == outEleTy)
2884 return true;
2885 // Output is unlimited polymorphic -> output dynamic type is the same as input
2886 // type.
2887 if (mlir::isa<mlir::NoneType>(outEleTy))
2888 return true;
2889 // Output/Input are derived types. Assuming input extends output type, output
2890 // dynamic type is the output static type, unless output is polymorphic.
2891 if (mlir::isa<fir::RecordType>(inputEleTy) &&
2892 mlir::isa<fir::RecordType>(outEleTy))
2893 return true;
2894 if (areCompatibleCharacterTypes(inputEleTy, outEleTy))
2895 return true;
2896 return false;
2899 llvm::LogicalResult fir::ReboxAssumedRankOp::verify() {
2900 mlir::Type inputType = getBox().getType();
2901 if (!mlir::isa<fir::BaseBoxType>(inputType) && !fir::isBoxAddress(inputType))
2902 return emitOpError("input must be a box or box address");
2903 mlir::Type inputEleTy =
2904 mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(inputType))
2905 .unwrapInnerType();
2906 mlir::Type outEleTy =
2907 mlir::cast<fir::BaseBoxType>(getType()).unwrapInnerType();
2908 if (!areCompatibleAssumedRankElementType(inputEleTy, outEleTy))
2909 return emitOpError("input and output element types are incompatible");
2910 return mlir::success();
2913 void fir::ReboxAssumedRankOp::getEffects(
2914 llvm::SmallVectorImpl<
2915 mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
2916 &effects) {
2917 mlir::OpOperand &inputBox = getBoxMutable();
2918 if (fir::isBoxAddress(inputBox.get().getType()))
2919 effects.emplace_back(mlir::MemoryEffects::Read::get(), &inputBox,
2920 mlir::SideEffects::DefaultResource::get());
2923 //===----------------------------------------------------------------------===//
2924 // ResultOp
2925 //===----------------------------------------------------------------------===//
2927 llvm::LogicalResult fir::ResultOp::verify() {
2928 auto *parentOp = (*this)->getParentOp();
2929 auto results = parentOp->getResults();
2930 auto operands = (*this)->getOperands();
2932 if (parentOp->getNumResults() != getNumOperands())
2933 return emitOpError() << "parent of result must have same arity";
2934 for (auto e : llvm::zip(results, operands))
2935 if (std::get<0>(e).getType() != std::get<1>(e).getType())
2936 return emitOpError() << "types mismatch between result op and its parent";
2937 return mlir::success();
2940 //===----------------------------------------------------------------------===//
2941 // SaveResultOp
2942 //===----------------------------------------------------------------------===//
2944 llvm::LogicalResult fir::SaveResultOp::verify() {
2945 auto resultType = getValue().getType();
2946 if (resultType != fir::dyn_cast_ptrEleTy(getMemref().getType()))
2947 return emitOpError("value type must match memory reference type");
2948 if (fir::isa_unknown_size_box(resultType))
2949 return emitOpError("cannot save !fir.box of unknown rank or type");
2951 if (mlir::isa<fir::BoxType>(resultType)) {
2952 if (getShape() || !getTypeparams().empty())
2953 return emitOpError(
2954 "must not have shape or length operands if the value is a fir.box");
2955 return mlir::success();
2958 // fir.record or fir.array case.
2959 unsigned shapeTyRank = 0;
2960 if (auto shapeVal = getShape()) {
2961 auto shapeTy = shapeVal.getType();
2962 if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy))
2963 shapeTyRank = s.getRank();
2964 else
2965 shapeTyRank = mlir::cast<fir::ShapeShiftType>(shapeTy).getRank();
2968 auto eleTy = resultType;
2969 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(resultType)) {
2970 if (seqTy.getDimension() != shapeTyRank)
2971 emitOpError("shape operand must be provided and have the value rank "
2972 "when the value is a fir.array");
2973 eleTy = seqTy.getEleTy();
2974 } else {
2975 if (shapeTyRank != 0)
2976 emitOpError(
2977 "shape operand should only be provided if the value is a fir.array");
2980 if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy)) {
2981 if (recTy.getNumLenParams() != getTypeparams().size())
2982 emitOpError("length parameters number must match with the value type "
2983 "length parameters");
2984 } else if (auto charTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) {
2985 if (getTypeparams().size() > 1)
2986 emitOpError("no more than one length parameter must be provided for "
2987 "character value");
2988 } else {
2989 if (!getTypeparams().empty())
2990 emitOpError("length parameters must not be provided for this value type");
2993 return mlir::success();
2996 //===----------------------------------------------------------------------===//
2997 // IntegralSwitchTerminator
2998 //===----------------------------------------------------------------------===//
2999 static constexpr llvm::StringRef getCompareOffsetAttr() {
3000 return "compare_operand_offsets";
3003 static constexpr llvm::StringRef getTargetOffsetAttr() {
3004 return "target_operand_offsets";
3007 template <typename OpT>
3008 static llvm::LogicalResult verifyIntegralSwitchTerminator(OpT op) {
3009 if (!mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType>(
3010 op.getSelector().getType()))
3011 return op.emitOpError("must be an integer");
3012 auto cases =
3013 op->template getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr()).getValue();
3014 auto count = op.getNumDest();
3015 if (count == 0)
3016 return op.emitOpError("must have at least one successor");
3017 if (op.getNumConditions() != count)
3018 return op.emitOpError("number of cases and targets don't match");
3019 if (op.targetOffsetSize() != count)
3020 return op.emitOpError("incorrect number of successor operand groups");
3021 for (decltype(count) i = 0; i != count; ++i) {
3022 if (!mlir::isa<mlir::IntegerAttr, mlir::UnitAttr>(cases[i]))
3023 return op.emitOpError("invalid case alternative");
3025 return mlir::success();
3028 static mlir::ParseResult parseIntegralSwitchTerminator(
3029 mlir::OpAsmParser &parser, mlir::OperationState &result,
3030 llvm::StringRef casesAttr, llvm::StringRef operandSegmentAttr) {
3031 mlir::OpAsmParser::UnresolvedOperand selector;
3032 mlir::Type type;
3033 if (fir::parseSelector(parser, result, selector, type))
3034 return mlir::failure();
3036 llvm::SmallVector<mlir::Attribute> ivalues;
3037 llvm::SmallVector<mlir::Block *> dests;
3038 llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;
3039 while (true) {
3040 mlir::Attribute ivalue; // Integer or Unit
3041 mlir::Block *dest;
3042 llvm::SmallVector<mlir::Value> destArg;
3043 mlir::NamedAttrList temp;
3044 if (parser.parseAttribute(ivalue, "i", temp) || parser.parseComma() ||
3045 parser.parseSuccessorAndUseList(dest, destArg))
3046 return mlir::failure();
3047 ivalues.push_back(ivalue);
3048 dests.push_back(dest);
3049 destArgs.push_back(destArg);
3050 if (!parser.parseOptionalRSquare())
3051 break;
3052 if (parser.parseComma())
3053 return mlir::failure();
3055 auto &bld = parser.getBuilder();
3056 result.addAttribute(casesAttr, bld.getArrayAttr(ivalues));
3057 llvm::SmallVector<int32_t> argOffs;
3058 int32_t sumArgs = 0;
3059 const auto count = dests.size();
3060 for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
3061 result.addSuccessors(dests[i]);
3062 result.addOperands(destArgs[i]);
3063 auto argSize = destArgs[i].size();
3064 argOffs.push_back(argSize);
3065 sumArgs += argSize;
3067 result.addAttribute(operandSegmentAttr,
3068 bld.getDenseI32ArrayAttr({1, 0, sumArgs}));
3069 result.addAttribute(getTargetOffsetAttr(), bld.getDenseI32ArrayAttr(argOffs));
3070 return mlir::success();
3073 template <typename OpT>
3074 static void printIntegralSwitchTerminator(OpT op, mlir::OpAsmPrinter &p) {
3075 p << ' ';
3076 p.printOperand(op.getSelector());
3077 p << " : " << op.getSelector().getType() << " [";
3078 auto cases =
3079 op->template getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr()).getValue();
3080 auto count = op.getNumConditions();
3081 for (decltype(count) i = 0; i != count; ++i) {
3082 if (i)
3083 p << ", ";
3084 auto &attr = cases[i];
3085 if (auto intAttr = mlir::dyn_cast_or_null<mlir::IntegerAttr>(attr))
3086 p << intAttr.getValue();
3087 else
3088 p.printAttribute(attr);
3089 p << ", ";
3090 op.printSuccessorAtIndex(p, i);
3092 p << ']';
3093 p.printOptionalAttrDict(
3094 op->getAttrs(), {op.getCasesAttr(), getCompareOffsetAttr(),
3095 getTargetOffsetAttr(), op.getOperandSegmentSizeAttr()});
3098 //===----------------------------------------------------------------------===//
3099 // SelectOp
3100 //===----------------------------------------------------------------------===//
3102 llvm::LogicalResult fir::SelectOp::verify() {
3103 return verifyIntegralSwitchTerminator(*this);
3106 mlir::ParseResult fir::SelectOp::parse(mlir::OpAsmParser &parser,
3107 mlir::OperationState &result) {
3108 return parseIntegralSwitchTerminator(parser, result, getCasesAttr(),
3109 getOperandSegmentSizeAttr());
3112 void fir::SelectOp::print(mlir::OpAsmPrinter &p) {
3113 printIntegralSwitchTerminator(*this, p);
3116 template <typename A, typename... AdditionalArgs>
3117 static A getSubOperands(unsigned pos, A allArgs, mlir::DenseI32ArrayAttr ranges,
3118 AdditionalArgs &&...additionalArgs) {
3119 unsigned start = 0;
3120 for (unsigned i = 0; i < pos; ++i)
3121 start += ranges[i];
3122 return allArgs.slice(start, ranges[pos],
3123 std::forward<AdditionalArgs>(additionalArgs)...);
3126 static mlir::MutableOperandRange
3127 getMutableSuccessorOperands(unsigned pos, mlir::MutableOperandRange operands,
3128 llvm::StringRef offsetAttr) {
3129 mlir::Operation *owner = operands.getOwner();
3130 mlir::NamedAttribute targetOffsetAttr =
3131 *owner->getAttrDictionary().getNamed(offsetAttr);
3132 return getSubOperands(
3133 pos, operands,
3134 mlir::cast<mlir::DenseI32ArrayAttr>(targetOffsetAttr.getValue()),
3135 mlir::MutableOperandRange::OperandSegment(pos, targetOffsetAttr));
3138 std::optional<mlir::OperandRange> fir::SelectOp::getCompareOperands(unsigned) {
3139 return {};
3142 std::optional<llvm::ArrayRef<mlir::Value>>
3143 fir::SelectOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {
3144 return {};
3147 mlir::SuccessorOperands fir::SelectOp::getSuccessorOperands(unsigned oper) {
3148 return mlir::SuccessorOperands(::getMutableSuccessorOperands(
3149 oper, getTargetArgsMutable(), getTargetOffsetAttr()));
3152 std::optional<llvm::ArrayRef<mlir::Value>>
3153 fir::SelectOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
3154 unsigned oper) {
3155 auto a =
3156 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3157 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3158 getOperandSegmentSizeAttr());
3159 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3162 std::optional<mlir::ValueRange>
3163 fir::SelectOp::getSuccessorOperands(mlir::ValueRange operands, unsigned oper) {
3164 auto a =
3165 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3166 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3167 getOperandSegmentSizeAttr());
3168 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3171 unsigned fir::SelectOp::targetOffsetSize() {
3172 return (*this)
3173 ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())
3174 .size();
3177 //===----------------------------------------------------------------------===//
3178 // SelectCaseOp
3179 //===----------------------------------------------------------------------===//
3181 std::optional<mlir::OperandRange>
3182 fir::SelectCaseOp::getCompareOperands(unsigned cond) {
3183 auto a =
3184 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr());
3185 return {getSubOperands(cond, getCompareArgs(), a)};
3188 std::optional<llvm::ArrayRef<mlir::Value>>
3189 fir::SelectCaseOp::getCompareOperands(llvm::ArrayRef<mlir::Value> operands,
3190 unsigned cond) {
3191 auto a =
3192 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr());
3193 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3194 getOperandSegmentSizeAttr());
3195 return {getSubOperands(cond, getSubOperands(1, operands, segments), a)};
3198 std::optional<mlir::ValueRange>
3199 fir::SelectCaseOp::getCompareOperands(mlir::ValueRange operands,
3200 unsigned cond) {
3201 auto a =
3202 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr());
3203 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3204 getOperandSegmentSizeAttr());
3205 return {getSubOperands(cond, getSubOperands(1, operands, segments), a)};
3208 mlir::SuccessorOperands fir::SelectCaseOp::getSuccessorOperands(unsigned oper) {
3209 return mlir::SuccessorOperands(::getMutableSuccessorOperands(
3210 oper, getTargetArgsMutable(), getTargetOffsetAttr()));
3213 std::optional<llvm::ArrayRef<mlir::Value>>
3214 fir::SelectCaseOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
3215 unsigned oper) {
3216 auto a =
3217 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3218 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3219 getOperandSegmentSizeAttr());
3220 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3223 std::optional<mlir::ValueRange>
3224 fir::SelectCaseOp::getSuccessorOperands(mlir::ValueRange operands,
3225 unsigned oper) {
3226 auto a =
3227 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3228 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3229 getOperandSegmentSizeAttr());
3230 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3233 // parser for fir.select_case Op
3234 mlir::ParseResult fir::SelectCaseOp::parse(mlir::OpAsmParser &parser,
3235 mlir::OperationState &result) {
3236 mlir::OpAsmParser::UnresolvedOperand selector;
3237 mlir::Type type;
3238 if (fir::parseSelector(parser, result, selector, type))
3239 return mlir::failure();
3241 llvm::SmallVector<mlir::Attribute> attrs;
3242 llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> opers;
3243 llvm::SmallVector<mlir::Block *> dests;
3244 llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;
3245 llvm::SmallVector<std::int32_t> argOffs;
3246 std::int32_t offSize = 0;
3247 while (true) {
3248 mlir::Attribute attr;
3249 mlir::Block *dest;
3250 llvm::SmallVector<mlir::Value> destArg;
3251 mlir::NamedAttrList temp;
3252 if (parser.parseAttribute(attr, "a", temp) || isValidCaseAttr(attr) ||
3253 parser.parseComma())
3254 return mlir::failure();
3255 attrs.push_back(attr);
3256 if (mlir::dyn_cast_or_null<mlir::UnitAttr>(attr)) {
3257 argOffs.push_back(0);
3258 } else if (mlir::dyn_cast_or_null<fir::ClosedIntervalAttr>(attr)) {
3259 mlir::OpAsmParser::UnresolvedOperand oper1;
3260 mlir::OpAsmParser::UnresolvedOperand oper2;
3261 if (parser.parseOperand(oper1) || parser.parseComma() ||
3262 parser.parseOperand(oper2) || parser.parseComma())
3263 return mlir::failure();
3264 opers.push_back(oper1);
3265 opers.push_back(oper2);
3266 argOffs.push_back(2);
3267 offSize += 2;
3268 } else {
3269 mlir::OpAsmParser::UnresolvedOperand oper;
3270 if (parser.parseOperand(oper) || parser.parseComma())
3271 return mlir::failure();
3272 opers.push_back(oper);
3273 argOffs.push_back(1);
3274 ++offSize;
3276 if (parser.parseSuccessorAndUseList(dest, destArg))
3277 return mlir::failure();
3278 dests.push_back(dest);
3279 destArgs.push_back(destArg);
3280 if (mlir::succeeded(parser.parseOptionalRSquare()))
3281 break;
3282 if (parser.parseComma())
3283 return mlir::failure();
3285 result.addAttribute(fir::SelectCaseOp::getCasesAttr(),
3286 parser.getBuilder().getArrayAttr(attrs));
3287 if (parser.resolveOperands(opers, type, result.operands))
3288 return mlir::failure();
3289 llvm::SmallVector<int32_t> targOffs;
3290 int32_t toffSize = 0;
3291 const auto count = dests.size();
3292 for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
3293 result.addSuccessors(dests[i]);
3294 result.addOperands(destArgs[i]);
3295 auto argSize = destArgs[i].size();
3296 targOffs.push_back(argSize);
3297 toffSize += argSize;
3299 auto &bld = parser.getBuilder();
3300 result.addAttribute(fir::SelectCaseOp::getOperandSegmentSizeAttr(),
3301 bld.getDenseI32ArrayAttr({1, offSize, toffSize}));
3302 result.addAttribute(getCompareOffsetAttr(),
3303 bld.getDenseI32ArrayAttr(argOffs));
3304 result.addAttribute(getTargetOffsetAttr(),
3305 bld.getDenseI32ArrayAttr(targOffs));
3306 return mlir::success();
3309 void fir::SelectCaseOp::print(mlir::OpAsmPrinter &p) {
3310 p << ' ';
3311 p.printOperand(getSelector());
3312 p << " : " << getSelector().getType() << " [";
3313 auto cases =
3314 getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
3315 auto count = getNumConditions();
3316 for (decltype(count) i = 0; i != count; ++i) {
3317 if (i)
3318 p << ", ";
3319 p << cases[i] << ", ";
3320 if (!mlir::isa<mlir::UnitAttr>(cases[i])) {
3321 auto caseArgs = *getCompareOperands(i);
3322 p.printOperand(*caseArgs.begin());
3323 p << ", ";
3324 if (mlir::isa<fir::ClosedIntervalAttr>(cases[i])) {
3325 p.printOperand(*(++caseArgs.begin()));
3326 p << ", ";
3329 printSuccessorAtIndex(p, i);
3331 p << ']';
3332 p.printOptionalAttrDict(getOperation()->getAttrs(),
3333 {getCasesAttr(), getCompareOffsetAttr(),
3334 getTargetOffsetAttr(), getOperandSegmentSizeAttr()});
3337 unsigned fir::SelectCaseOp::compareOffsetSize() {
3338 return (*this)
3339 ->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr())
3340 .size();
3343 unsigned fir::SelectCaseOp::targetOffsetSize() {
3344 return (*this)
3345 ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())
3346 .size();
3349 void fir::SelectCaseOp::build(mlir::OpBuilder &builder,
3350 mlir::OperationState &result,
3351 mlir::Value selector,
3352 llvm::ArrayRef<mlir::Attribute> compareAttrs,
3353 llvm::ArrayRef<mlir::ValueRange> cmpOperands,
3354 llvm::ArrayRef<mlir::Block *> destinations,
3355 llvm::ArrayRef<mlir::ValueRange> destOperands,
3356 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
3357 result.addOperands(selector);
3358 result.addAttribute(getCasesAttr(), builder.getArrayAttr(compareAttrs));
3359 llvm::SmallVector<int32_t> operOffs;
3360 int32_t operSize = 0;
3361 for (auto attr : compareAttrs) {
3362 if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {
3363 operOffs.push_back(2);
3364 operSize += 2;
3365 } else if (mlir::isa<mlir::UnitAttr>(attr)) {
3366 operOffs.push_back(0);
3367 } else {
3368 operOffs.push_back(1);
3369 ++operSize;
3372 for (auto ops : cmpOperands)
3373 result.addOperands(ops);
3374 result.addAttribute(getCompareOffsetAttr(),
3375 builder.getDenseI32ArrayAttr(operOffs));
3376 const auto count = destinations.size();
3377 for (auto d : destinations)
3378 result.addSuccessors(d);
3379 const auto opCount = destOperands.size();
3380 llvm::SmallVector<std::int32_t> argOffs;
3381 std::int32_t sumArgs = 0;
3382 for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
3383 if (i < opCount) {
3384 result.addOperands(destOperands[i]);
3385 const auto argSz = destOperands[i].size();
3386 argOffs.push_back(argSz);
3387 sumArgs += argSz;
3388 } else {
3389 argOffs.push_back(0);
3392 result.addAttribute(getOperandSegmentSizeAttr(),
3393 builder.getDenseI32ArrayAttr({1, operSize, sumArgs}));
3394 result.addAttribute(getTargetOffsetAttr(),
3395 builder.getDenseI32ArrayAttr(argOffs));
3396 result.addAttributes(attributes);
3399 /// This builder has a slightly simplified interface in that the list of
3400 /// operands need not be partitioned by the builder. Instead the operands are
3401 /// partitioned here, before being passed to the default builder. This
3402 /// partitioning is unchecked, so can go awry on bad input.
3403 void fir::SelectCaseOp::build(mlir::OpBuilder &builder,
3404 mlir::OperationState &result,
3405 mlir::Value selector,
3406 llvm::ArrayRef<mlir::Attribute> compareAttrs,
3407 llvm::ArrayRef<mlir::Value> cmpOpList,
3408 llvm::ArrayRef<mlir::Block *> destinations,
3409 llvm::ArrayRef<mlir::ValueRange> destOperands,
3410 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
3411 llvm::SmallVector<mlir::ValueRange> cmpOpers;
3412 auto iter = cmpOpList.begin();
3413 for (auto &attr : compareAttrs) {
3414 if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {
3415 cmpOpers.push_back(mlir::ValueRange({iter, iter + 2}));
3416 iter += 2;
3417 } else if (mlir::isa<mlir::UnitAttr>(attr)) {
3418 cmpOpers.push_back(mlir::ValueRange{});
3419 } else {
3420 cmpOpers.push_back(mlir::ValueRange({iter, iter + 1}));
3421 ++iter;
3424 build(builder, result, selector, compareAttrs, cmpOpers, destinations,
3425 destOperands, attributes);
3428 llvm::LogicalResult fir::SelectCaseOp::verify() {
3429 if (!mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType,
3430 fir::LogicalType, fir::CharacterType>(getSelector().getType()))
3431 return emitOpError("must be an integer, character, or logical");
3432 auto cases =
3433 getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
3434 auto count = getNumDest();
3435 if (count == 0)
3436 return emitOpError("must have at least one successor");
3437 if (getNumConditions() != count)
3438 return emitOpError("number of conditions and successors don't match");
3439 if (compareOffsetSize() != count)
3440 return emitOpError("incorrect number of compare operand groups");
3441 if (targetOffsetSize() != count)
3442 return emitOpError("incorrect number of successor operand groups");
3443 for (decltype(count) i = 0; i != count; ++i) {
3444 auto &attr = cases[i];
3445 if (!(mlir::isa<fir::PointIntervalAttr>(attr) ||
3446 mlir::isa<fir::LowerBoundAttr>(attr) ||
3447 mlir::isa<fir::UpperBoundAttr>(attr) ||
3448 mlir::isa<fir::ClosedIntervalAttr>(attr) ||
3449 mlir::isa<mlir::UnitAttr>(attr)))
3450 return emitOpError("incorrect select case attribute type");
3452 return mlir::success();
3455 //===----------------------------------------------------------------------===//
3456 // SelectRankOp
3457 //===----------------------------------------------------------------------===//
3459 llvm::LogicalResult fir::SelectRankOp::verify() {
3460 return verifyIntegralSwitchTerminator(*this);
3463 mlir::ParseResult fir::SelectRankOp::parse(mlir::OpAsmParser &parser,
3464 mlir::OperationState &result) {
3465 return parseIntegralSwitchTerminator(parser, result, getCasesAttr(),
3466 getOperandSegmentSizeAttr());
3469 void fir::SelectRankOp::print(mlir::OpAsmPrinter &p) {
3470 printIntegralSwitchTerminator(*this, p);
3473 std::optional<mlir::OperandRange>
3474 fir::SelectRankOp::getCompareOperands(unsigned) {
3475 return {};
3478 std::optional<llvm::ArrayRef<mlir::Value>>
3479 fir::SelectRankOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {
3480 return {};
3483 mlir::SuccessorOperands fir::SelectRankOp::getSuccessorOperands(unsigned oper) {
3484 return mlir::SuccessorOperands(::getMutableSuccessorOperands(
3485 oper, getTargetArgsMutable(), getTargetOffsetAttr()));
3488 std::optional<llvm::ArrayRef<mlir::Value>>
3489 fir::SelectRankOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
3490 unsigned oper) {
3491 auto a =
3492 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3493 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3494 getOperandSegmentSizeAttr());
3495 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3498 std::optional<mlir::ValueRange>
3499 fir::SelectRankOp::getSuccessorOperands(mlir::ValueRange operands,
3500 unsigned oper) {
3501 auto a =
3502 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3503 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3504 getOperandSegmentSizeAttr());
3505 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3508 unsigned fir::SelectRankOp::targetOffsetSize() {
3509 return (*this)
3510 ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())
3511 .size();
3514 //===----------------------------------------------------------------------===//
3515 // SelectTypeOp
3516 //===----------------------------------------------------------------------===//
3518 std::optional<mlir::OperandRange>
3519 fir::SelectTypeOp::getCompareOperands(unsigned) {
3520 return {};
3523 std::optional<llvm::ArrayRef<mlir::Value>>
3524 fir::SelectTypeOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {
3525 return {};
3528 mlir::SuccessorOperands fir::SelectTypeOp::getSuccessorOperands(unsigned oper) {
3529 return mlir::SuccessorOperands(::getMutableSuccessorOperands(
3530 oper, getTargetArgsMutable(), getTargetOffsetAttr()));
3533 std::optional<llvm::ArrayRef<mlir::Value>>
3534 fir::SelectTypeOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
3535 unsigned oper) {
3536 auto a =
3537 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3538 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3539 getOperandSegmentSizeAttr());
3540 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3543 std::optional<mlir::ValueRange>
3544 fir::SelectTypeOp::getSuccessorOperands(mlir::ValueRange operands,
3545 unsigned oper) {
3546 auto a =
3547 (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());
3548 auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(
3549 getOperandSegmentSizeAttr());
3550 return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
3553 mlir::ParseResult fir::SelectTypeOp::parse(mlir::OpAsmParser &parser,
3554 mlir::OperationState &result) {
3555 mlir::OpAsmParser::UnresolvedOperand selector;
3556 mlir::Type type;
3557 if (fir::parseSelector(parser, result, selector, type))
3558 return mlir::failure();
3560 llvm::SmallVector<mlir::Attribute> attrs;
3561 llvm::SmallVector<mlir::Block *> dests;
3562 llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;
3563 while (true) {
3564 mlir::Attribute attr;
3565 mlir::Block *dest;
3566 llvm::SmallVector<mlir::Value> destArg;
3567 mlir::NamedAttrList temp;
3568 if (parser.parseAttribute(attr, "a", temp) || parser.parseComma() ||
3569 parser.parseSuccessorAndUseList(dest, destArg))
3570 return mlir::failure();
3571 attrs.push_back(attr);
3572 dests.push_back(dest);
3573 destArgs.push_back(destArg);
3574 if (mlir::succeeded(parser.parseOptionalRSquare()))
3575 break;
3576 if (parser.parseComma())
3577 return mlir::failure();
3579 auto &bld = parser.getBuilder();
3580 result.addAttribute(fir::SelectTypeOp::getCasesAttr(),
3581 bld.getArrayAttr(attrs));
3582 llvm::SmallVector<int32_t> argOffs;
3583 int32_t offSize = 0;
3584 const auto count = dests.size();
3585 for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
3586 result.addSuccessors(dests[i]);
3587 result.addOperands(destArgs[i]);
3588 auto argSize = destArgs[i].size();
3589 argOffs.push_back(argSize);
3590 offSize += argSize;
3592 result.addAttribute(fir::SelectTypeOp::getOperandSegmentSizeAttr(),
3593 bld.getDenseI32ArrayAttr({1, 0, offSize}));
3594 result.addAttribute(getTargetOffsetAttr(), bld.getDenseI32ArrayAttr(argOffs));
3595 return mlir::success();
3598 unsigned fir::SelectTypeOp::targetOffsetSize() {
3599 return (*this)
3600 ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())
3601 .size();
3604 void fir::SelectTypeOp::print(mlir::OpAsmPrinter &p) {
3605 p << ' ';
3606 p.printOperand(getSelector());
3607 p << " : " << getSelector().getType() << " [";
3608 auto cases =
3609 getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
3610 auto count = getNumConditions();
3611 for (decltype(count) i = 0; i != count; ++i) {
3612 if (i)
3613 p << ", ";
3614 p << cases[i] << ", ";
3615 printSuccessorAtIndex(p, i);
3617 p << ']';
3618 p.printOptionalAttrDict(getOperation()->getAttrs(),
3619 {getCasesAttr(), getCompareOffsetAttr(),
3620 getTargetOffsetAttr(),
3621 fir::SelectTypeOp::getOperandSegmentSizeAttr()});
3624 llvm::LogicalResult fir::SelectTypeOp::verify() {
3625 if (!mlir::isa<fir::BaseBoxType>(getSelector().getType()))
3626 return emitOpError("must be a fir.class or fir.box type");
3627 if (auto boxType = mlir::dyn_cast<fir::BoxType>(getSelector().getType()))
3628 if (!mlir::isa<mlir::NoneType>(boxType.getEleTy()))
3629 return emitOpError("selector must be polymorphic");
3630 auto typeGuardAttr = getCases();
3631 for (unsigned idx = 0; idx < typeGuardAttr.size(); ++idx)
3632 if (mlir::isa<mlir::UnitAttr>(typeGuardAttr[idx]) &&
3633 idx != typeGuardAttr.size() - 1)
3634 return emitOpError("default must be the last attribute");
3635 auto count = getNumDest();
3636 if (count == 0)
3637 return emitOpError("must have at least one successor");
3638 if (getNumConditions() != count)
3639 return emitOpError("number of conditions and successors don't match");
3640 if (targetOffsetSize() != count)
3641 return emitOpError("incorrect number of successor operand groups");
3642 for (unsigned i = 0; i != count; ++i) {
3643 if (!mlir::isa<fir::ExactTypeAttr, fir::SubclassAttr, mlir::UnitAttr>(
3644 typeGuardAttr[i]))
3645 return emitOpError("invalid type-case alternative");
3647 return mlir::success();
3650 void fir::SelectTypeOp::build(mlir::OpBuilder &builder,
3651 mlir::OperationState &result,
3652 mlir::Value selector,
3653 llvm::ArrayRef<mlir::Attribute> typeOperands,
3654 llvm::ArrayRef<mlir::Block *> destinations,
3655 llvm::ArrayRef<mlir::ValueRange> destOperands,
3656 llvm::ArrayRef<mlir::NamedAttribute> attributes) {
3657 result.addOperands(selector);
3658 result.addAttribute(getCasesAttr(), builder.getArrayAttr(typeOperands));
3659 const auto count = destinations.size();
3660 for (mlir::Block *dest : destinations)
3661 result.addSuccessors(dest);
3662 const auto opCount = destOperands.size();
3663 llvm::SmallVector<int32_t> argOffs;
3664 int32_t sumArgs = 0;
3665 for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
3666 if (i < opCount) {
3667 result.addOperands(destOperands[i]);
3668 const auto argSz = destOperands[i].size();
3669 argOffs.push_back(argSz);
3670 sumArgs += argSz;
3671 } else {
3672 argOffs.push_back(0);
3675 result.addAttribute(getOperandSegmentSizeAttr(),
3676 builder.getDenseI32ArrayAttr({1, 0, sumArgs}));
3677 result.addAttribute(getTargetOffsetAttr(),
3678 builder.getDenseI32ArrayAttr(argOffs));
3679 result.addAttributes(attributes);
3682 //===----------------------------------------------------------------------===//
3683 // ShapeOp
3684 //===----------------------------------------------------------------------===//
3686 llvm::LogicalResult fir::ShapeOp::verify() {
3687 auto size = getExtents().size();
3688 auto shapeTy = mlir::dyn_cast<fir::ShapeType>(getType());
3689 assert(shapeTy && "must be a shape type");
3690 if (shapeTy.getRank() != size)
3691 return emitOpError("shape type rank mismatch");
3692 return mlir::success();
3695 void fir::ShapeOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3696 mlir::ValueRange extents) {
3697 auto type = fir::ShapeType::get(builder.getContext(), extents.size());
3698 build(builder, result, type, extents);
3701 //===----------------------------------------------------------------------===//
3702 // ShapeShiftOp
3703 //===----------------------------------------------------------------------===//
3705 llvm::LogicalResult fir::ShapeShiftOp::verify() {
3706 auto size = getPairs().size();
3707 if (size < 2 || size > 16 * 2)
3708 return emitOpError("incorrect number of args");
3709 if (size % 2 != 0)
3710 return emitOpError("requires a multiple of 2 args");
3711 auto shapeTy = mlir::dyn_cast<fir::ShapeShiftType>(getType());
3712 assert(shapeTy && "must be a shape shift type");
3713 if (shapeTy.getRank() * 2 != size)
3714 return emitOpError("shape type rank mismatch");
3715 return mlir::success();
3718 //===----------------------------------------------------------------------===//
3719 // ShiftOp
3720 //===----------------------------------------------------------------------===//
3722 llvm::LogicalResult fir::ShiftOp::verify() {
3723 auto size = getOrigins().size();
3724 auto shiftTy = mlir::dyn_cast<fir::ShiftType>(getType());
3725 assert(shiftTy && "must be a shift type");
3726 if (shiftTy.getRank() != size)
3727 return emitOpError("shift type rank mismatch");
3728 return mlir::success();
3731 //===----------------------------------------------------------------------===//
3732 // SliceOp
3733 //===----------------------------------------------------------------------===//
3735 void fir::SliceOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3736 mlir::ValueRange trips, mlir::ValueRange path,
3737 mlir::ValueRange substr) {
3738 const auto rank = trips.size() / 3;
3739 auto sliceTy = fir::SliceType::get(builder.getContext(), rank);
3740 build(builder, result, sliceTy, trips, path, substr);
3743 /// Return the output rank of a slice op. The output rank must be between 1 and
3744 /// the rank of the array being sliced (inclusive).
3745 unsigned fir::SliceOp::getOutputRank(mlir::ValueRange triples) {
3746 unsigned rank = 0;
3747 if (!triples.empty()) {
3748 for (unsigned i = 1, end = triples.size(); i < end; i += 3) {
3749 auto *op = triples[i].getDefiningOp();
3750 if (!mlir::isa_and_nonnull<fir::UndefOp>(op))
3751 ++rank;
3753 assert(rank > 0);
3755 return rank;
3758 llvm::LogicalResult fir::SliceOp::verify() {
3759 auto size = getTriples().size();
3760 if (size < 3 || size > 16 * 3)
3761 return emitOpError("incorrect number of args for triple");
3762 if (size % 3 != 0)
3763 return emitOpError("requires a multiple of 3 args");
3764 auto sliceTy = mlir::dyn_cast<fir::SliceType>(getType());
3765 assert(sliceTy && "must be a slice type");
3766 if (sliceTy.getRank() * 3 != size)
3767 return emitOpError("slice type rank mismatch");
3768 return mlir::success();
3771 //===----------------------------------------------------------------------===//
3772 // StoreOp
3773 //===----------------------------------------------------------------------===//
3775 mlir::Type fir::StoreOp::elementType(mlir::Type refType) {
3776 return fir::dyn_cast_ptrEleTy(refType);
3779 mlir::ParseResult fir::StoreOp::parse(mlir::OpAsmParser &parser,
3780 mlir::OperationState &result) {
3781 mlir::Type type;
3782 mlir::OpAsmParser::UnresolvedOperand oper;
3783 mlir::OpAsmParser::UnresolvedOperand store;
3784 if (parser.parseOperand(oper) || parser.parseKeyword("to") ||
3785 parser.parseOperand(store) ||
3786 parser.parseOptionalAttrDict(result.attributes) ||
3787 parser.parseColonType(type) ||
3788 parser.resolveOperand(oper, fir::StoreOp::elementType(type),
3789 result.operands) ||
3790 parser.resolveOperand(store, type, result.operands))
3791 return mlir::failure();
3792 return mlir::success();
3795 void fir::StoreOp::print(mlir::OpAsmPrinter &p) {
3796 p << ' ';
3797 p.printOperand(getValue());
3798 p << " to ";
3799 p.printOperand(getMemref());
3800 p.printOptionalAttrDict(getOperation()->getAttrs(), {});
3801 p << " : " << getMemref().getType();
3804 llvm::LogicalResult fir::StoreOp::verify() {
3805 if (getValue().getType() != fir::dyn_cast_ptrEleTy(getMemref().getType()))
3806 return emitOpError("store value type must match memory reference type");
3807 return mlir::success();
3810 void fir::StoreOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3811 mlir::Value value, mlir::Value memref) {
3812 build(builder, result, value, memref, {});
3815 //===----------------------------------------------------------------------===//
3816 // StringLitOp
3817 //===----------------------------------------------------------------------===//
3819 inline fir::CharacterType::KindTy stringLitOpGetKind(fir::StringLitOp op) {
3820 auto eleTy = mlir::cast<fir::SequenceType>(op.getType()).getElementType();
3821 return mlir::cast<fir::CharacterType>(eleTy).getFKind();
3824 bool fir::StringLitOp::isWideValue() { return stringLitOpGetKind(*this) != 1; }
3826 static mlir::NamedAttribute
3827 mkNamedIntegerAttr(mlir::OpBuilder &builder, llvm::StringRef name, int64_t v) {
3828 assert(v > 0);
3829 return builder.getNamedAttr(
3830 name, builder.getIntegerAttr(builder.getIntegerType(64), v));
3833 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3834 mlir::OperationState &result,
3835 fir::CharacterType inType, llvm::StringRef val,
3836 std::optional<int64_t> len) {
3837 auto valAttr = builder.getNamedAttr(value(), builder.getStringAttr(val));
3838 int64_t length = len ? *len : inType.getLen();
3839 auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3840 result.addAttributes({valAttr, lenAttr});
3841 result.addTypes(inType);
3844 template <typename C>
3845 static mlir::ArrayAttr convertToArrayAttr(mlir::OpBuilder &builder,
3846 llvm::ArrayRef<C> xlist) {
3847 llvm::SmallVector<mlir::Attribute> attrs;
3848 auto ty = builder.getIntegerType(8 * sizeof(C));
3849 for (auto ch : xlist)
3850 attrs.push_back(builder.getIntegerAttr(ty, ch));
3851 return builder.getArrayAttr(attrs);
3854 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3855 mlir::OperationState &result,
3856 fir::CharacterType inType,
3857 llvm::ArrayRef<char> vlist,
3858 std::optional<std::int64_t> len) {
3859 auto valAttr =
3860 builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));
3861 std::int64_t length = len ? *len : inType.getLen();
3862 auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3863 result.addAttributes({valAttr, lenAttr});
3864 result.addTypes(inType);
3867 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3868 mlir::OperationState &result,
3869 fir::CharacterType inType,
3870 llvm::ArrayRef<char16_t> vlist,
3871 std::optional<std::int64_t> len) {
3872 auto valAttr =
3873 builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));
3874 std::int64_t length = len ? *len : inType.getLen();
3875 auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3876 result.addAttributes({valAttr, lenAttr});
3877 result.addTypes(inType);
3880 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3881 mlir::OperationState &result,
3882 fir::CharacterType inType,
3883 llvm::ArrayRef<char32_t> vlist,
3884 std::optional<std::int64_t> len) {
3885 auto valAttr =
3886 builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));
3887 std::int64_t length = len ? *len : inType.getLen();
3888 auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3889 result.addAttributes({valAttr, lenAttr});
3890 result.addTypes(inType);
3893 mlir::ParseResult fir::StringLitOp::parse(mlir::OpAsmParser &parser,
3894 mlir::OperationState &result) {
3895 auto &builder = parser.getBuilder();
3896 mlir::Attribute val;
3897 mlir::NamedAttrList attrs;
3898 llvm::SMLoc trailingTypeLoc;
3899 if (parser.parseAttribute(val, "fake", attrs))
3900 return mlir::failure();
3901 if (auto v = mlir::dyn_cast<mlir::StringAttr>(val))
3902 result.attributes.push_back(
3903 builder.getNamedAttr(fir::StringLitOp::value(), v));
3904 else if (auto v = mlir::dyn_cast<mlir::DenseElementsAttr>(val))
3905 result.attributes.push_back(
3906 builder.getNamedAttr(fir::StringLitOp::xlist(), v));
3907 else if (auto v = mlir::dyn_cast<mlir::ArrayAttr>(val))
3908 result.attributes.push_back(
3909 builder.getNamedAttr(fir::StringLitOp::xlist(), v));
3910 else
3911 return parser.emitError(parser.getCurrentLocation(),
3912 "found an invalid constant");
3913 mlir::IntegerAttr sz;
3914 mlir::Type type;
3915 if (parser.parseLParen() ||
3916 parser.parseAttribute(sz, fir::StringLitOp::size(), result.attributes) ||
3917 parser.parseRParen() || parser.getCurrentLocation(&trailingTypeLoc) ||
3918 parser.parseColonType(type))
3919 return mlir::failure();
3920 auto charTy = mlir::dyn_cast<fir::CharacterType>(type);
3921 if (!charTy)
3922 return parser.emitError(trailingTypeLoc, "must have character type");
3923 type = fir::CharacterType::get(builder.getContext(), charTy.getFKind(),
3924 sz.getInt());
3925 if (!type || parser.addTypesToList(type, result.types))
3926 return mlir::failure();
3927 return mlir::success();
3930 void fir::StringLitOp::print(mlir::OpAsmPrinter &p) {
3931 p << ' ' << getValue() << '(';
3932 p << mlir::cast<mlir::IntegerAttr>(getSize()).getValue() << ") : ";
3933 p.printType(getType());
3936 llvm::LogicalResult fir::StringLitOp::verify() {
3937 if (mlir::cast<mlir::IntegerAttr>(getSize()).getValue().isNegative())
3938 return emitOpError("size must be non-negative");
3939 if (auto xl = getOperation()->getAttr(fir::StringLitOp::xlist())) {
3940 if (auto xList = mlir::dyn_cast<mlir::ArrayAttr>(xl)) {
3941 for (auto a : xList)
3942 if (!mlir::isa<mlir::IntegerAttr>(a))
3943 return emitOpError("values in initializer must be integers");
3944 } else if (mlir::isa<mlir::DenseElementsAttr>(xl)) {
3945 // do nothing
3946 } else {
3947 return emitOpError("has unexpected attribute");
3950 return mlir::success();
3953 //===----------------------------------------------------------------------===//
3954 // UnboxProcOp
3955 //===----------------------------------------------------------------------===//
3957 llvm::LogicalResult fir::UnboxProcOp::verify() {
3958 if (auto eleTy = fir::dyn_cast_ptrEleTy(getRefTuple().getType()))
3959 if (mlir::isa<mlir::TupleType>(eleTy))
3960 return mlir::success();
3961 return emitOpError("second output argument has bad type");
3964 //===----------------------------------------------------------------------===//
3965 // IfOp
3966 //===----------------------------------------------------------------------===//
3968 void fir::IfOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3969 mlir::Value cond, bool withElseRegion) {
3970 build(builder, result, std::nullopt, cond, withElseRegion);
3973 void fir::IfOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3974 mlir::TypeRange resultTypes, mlir::Value cond,
3975 bool withElseRegion) {
3976 result.addOperands(cond);
3977 result.addTypes(resultTypes);
3979 mlir::Region *thenRegion = result.addRegion();
3980 thenRegion->push_back(new mlir::Block());
3981 if (resultTypes.empty())
3982 IfOp::ensureTerminator(*thenRegion, builder, result.location);
3984 mlir::Region *elseRegion = result.addRegion();
3985 if (withElseRegion) {
3986 elseRegion->push_back(new mlir::Block());
3987 if (resultTypes.empty())
3988 IfOp::ensureTerminator(*elseRegion, builder, result.location);
3992 // These 3 functions copied from scf.if implementation.
3994 /// Given the region at `index`, or the parent operation if `index` is None,
3995 /// return the successor regions. These are the regions that may be selected
3996 /// during the flow of control.
3997 void fir::IfOp::getSuccessorRegions(
3998 mlir::RegionBranchPoint point,
3999 llvm::SmallVectorImpl<mlir::RegionSuccessor> &regions) {
4000 // The `then` and the `else` region branch back to the parent operation.
4001 if (!point.isParent()) {
4002 regions.push_back(mlir::RegionSuccessor(getResults()));
4003 return;
4006 // Don't consider the else region if it is empty.
4007 regions.push_back(mlir::RegionSuccessor(&getThenRegion()));
4009 // Don't consider the else region if it is empty.
4010 mlir::Region *elseRegion = &this->getElseRegion();
4011 if (elseRegion->empty())
4012 regions.push_back(mlir::RegionSuccessor());
4013 else
4014 regions.push_back(mlir::RegionSuccessor(elseRegion));
4017 void fir::IfOp::getEntrySuccessorRegions(
4018 llvm::ArrayRef<mlir::Attribute> operands,
4019 llvm::SmallVectorImpl<mlir::RegionSuccessor> &regions) {
4020 FoldAdaptor adaptor(operands);
4021 auto boolAttr =
4022 mlir::dyn_cast_or_null<mlir::BoolAttr>(adaptor.getCondition());
4023 if (!boolAttr || boolAttr.getValue())
4024 regions.emplace_back(&getThenRegion());
4026 // If the else region is empty, execution continues after the parent op.
4027 if (!boolAttr || !boolAttr.getValue()) {
4028 if (!getElseRegion().empty())
4029 regions.emplace_back(&getElseRegion());
4030 else
4031 regions.emplace_back(getResults());
4035 void fir::IfOp::getRegionInvocationBounds(
4036 llvm::ArrayRef<mlir::Attribute> operands,
4037 llvm::SmallVectorImpl<mlir::InvocationBounds> &invocationBounds) {
4038 if (auto cond = mlir::dyn_cast_or_null<mlir::BoolAttr>(operands[0])) {
4039 // If the condition is known, then one region is known to be executed once
4040 // and the other zero times.
4041 invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);
4042 invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);
4043 } else {
4044 // Non-constant condition. Each region may be executed 0 or 1 times.
4045 invocationBounds.assign(2, {0, 1});
4049 mlir::ParseResult fir::IfOp::parse(mlir::OpAsmParser &parser,
4050 mlir::OperationState &result) {
4051 result.regions.reserve(2);
4052 mlir::Region *thenRegion = result.addRegion();
4053 mlir::Region *elseRegion = result.addRegion();
4055 auto &builder = parser.getBuilder();
4056 mlir::OpAsmParser::UnresolvedOperand cond;
4057 mlir::Type i1Type = builder.getIntegerType(1);
4058 if (parser.parseOperand(cond) ||
4059 parser.resolveOperand(cond, i1Type, result.operands))
4060 return mlir::failure();
4062 if (parser.parseOptionalArrowTypeList(result.types))
4063 return mlir::failure();
4065 if (parser.parseRegion(*thenRegion, {}, {}))
4066 return mlir::failure();
4067 fir::IfOp::ensureTerminator(*thenRegion, parser.getBuilder(),
4068 result.location);
4070 if (mlir::succeeded(parser.parseOptionalKeyword("else"))) {
4071 if (parser.parseRegion(*elseRegion, {}, {}))
4072 return mlir::failure();
4073 fir::IfOp::ensureTerminator(*elseRegion, parser.getBuilder(),
4074 result.location);
4077 // Parse the optional attribute list.
4078 if (parser.parseOptionalAttrDict(result.attributes))
4079 return mlir::failure();
4080 return mlir::success();
4083 llvm::LogicalResult fir::IfOp::verify() {
4084 if (getNumResults() != 0 && getElseRegion().empty())
4085 return emitOpError("must have an else block if defining values");
4087 return mlir::success();
4090 void fir::IfOp::print(mlir::OpAsmPrinter &p) {
4091 bool printBlockTerminators = false;
4092 p << ' ' << getCondition();
4093 if (!getResults().empty()) {
4094 p << " -> (" << getResultTypes() << ')';
4095 printBlockTerminators = true;
4097 p << ' ';
4098 p.printRegion(getThenRegion(), /*printEntryBlockArgs=*/false,
4099 printBlockTerminators);
4101 // Print the 'else' regions if it exists and has a block.
4102 auto &otherReg = getElseRegion();
4103 if (!otherReg.empty()) {
4104 p << " else ";
4105 p.printRegion(otherReg, /*printEntryBlockArgs=*/false,
4106 printBlockTerminators);
4108 p.printOptionalAttrDict((*this)->getAttrs());
4111 void fir::IfOp::resultToSourceOps(llvm::SmallVectorImpl<mlir::Value> &results,
4112 unsigned resultNum) {
4113 auto *term = getThenRegion().front().getTerminator();
4114 if (resultNum < term->getNumOperands())
4115 results.push_back(term->getOperand(resultNum));
4116 term = getElseRegion().front().getTerminator();
4117 if (resultNum < term->getNumOperands())
4118 results.push_back(term->getOperand(resultNum));
4121 //===----------------------------------------------------------------------===//
4122 // BoxOffsetOp
4123 //===----------------------------------------------------------------------===//
4125 llvm::LogicalResult fir::BoxOffsetOp::verify() {
4126 auto boxType = mlir::dyn_cast_or_null<fir::BaseBoxType>(
4127 fir::dyn_cast_ptrEleTy(getBoxRef().getType()));
4128 if (!boxType)
4129 return emitOpError("box_ref operand must have !fir.ref<!fir.box<T>> type");
4130 if (getField() != fir::BoxFieldAttr::base_addr &&
4131 getField() != fir::BoxFieldAttr::derived_type)
4132 return emitOpError("cannot address provided field");
4133 if (getField() == fir::BoxFieldAttr::derived_type)
4134 if (!fir::boxHasAddendum(boxType))
4135 return emitOpError("can only address derived_type field of derived type "
4136 "or unlimited polymorphic fir.box");
4137 return mlir::success();
4140 void fir::BoxOffsetOp::build(mlir::OpBuilder &builder,
4141 mlir::OperationState &result, mlir::Value boxRef,
4142 fir::BoxFieldAttr field) {
4143 mlir::Type valueType =
4144 fir::unwrapPassByRefType(fir::unwrapRefType(boxRef.getType()));
4145 mlir::Type resultType = valueType;
4146 if (field == fir::BoxFieldAttr::base_addr)
4147 resultType = fir::LLVMPointerType::get(fir::ReferenceType::get(valueType));
4148 else if (field == fir::BoxFieldAttr::derived_type)
4149 resultType = fir::LLVMPointerType::get(
4150 fir::TypeDescType::get(fir::unwrapSequenceType(valueType)));
4151 build(builder, result, {resultType}, boxRef, field);
4154 //===----------------------------------------------------------------------===//
4156 mlir::ParseResult fir::isValidCaseAttr(mlir::Attribute attr) {
4157 if (mlir::isa<mlir::UnitAttr, fir::ClosedIntervalAttr, fir::PointIntervalAttr,
4158 fir::LowerBoundAttr, fir::UpperBoundAttr>(attr))
4159 return mlir::success();
4160 return mlir::failure();
4163 unsigned fir::getCaseArgumentOffset(llvm::ArrayRef<mlir::Attribute> cases,
4164 unsigned dest) {
4165 unsigned o = 0;
4166 for (unsigned i = 0; i < dest; ++i) {
4167 auto &attr = cases[i];
4168 if (!mlir::dyn_cast_or_null<mlir::UnitAttr>(attr)) {
4169 ++o;
4170 if (mlir::dyn_cast_or_null<fir::ClosedIntervalAttr>(attr))
4171 ++o;
4174 return o;
4177 mlir::ParseResult
4178 fir::parseSelector(mlir::OpAsmParser &parser, mlir::OperationState &result,
4179 mlir::OpAsmParser::UnresolvedOperand &selector,
4180 mlir::Type &type) {
4181 if (parser.parseOperand(selector) || parser.parseColonType(type) ||
4182 parser.resolveOperand(selector, type, result.operands) ||
4183 parser.parseLSquare())
4184 return mlir::failure();
4185 return mlir::success();
4188 mlir::func::FuncOp fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module,
4189 llvm::StringRef name,
4190 mlir::FunctionType type,
4191 llvm::ArrayRef<mlir::NamedAttribute> attrs,
4192 const mlir::SymbolTable *symbolTable) {
4193 if (symbolTable)
4194 if (auto f = symbolTable->lookup<mlir::func::FuncOp>(name)) {
4195 #ifdef EXPENSIVE_CHECKS
4196 assert(f == module.lookupSymbol<mlir::func::FuncOp>(name) &&
4197 "symbolTable and module out of sync");
4198 #endif
4199 return f;
4201 if (auto f = module.lookupSymbol<mlir::func::FuncOp>(name))
4202 return f;
4203 mlir::OpBuilder modBuilder(module.getBodyRegion());
4204 modBuilder.setInsertionPointToEnd(module.getBody());
4205 auto result = modBuilder.create<mlir::func::FuncOp>(loc, name, type, attrs);
4206 result.setVisibility(mlir::SymbolTable::Visibility::Private);
4207 return result;
4210 fir::GlobalOp fir::createGlobalOp(mlir::Location loc, mlir::ModuleOp module,
4211 llvm::StringRef name, mlir::Type type,
4212 llvm::ArrayRef<mlir::NamedAttribute> attrs,
4213 const mlir::SymbolTable *symbolTable) {
4214 if (symbolTable)
4215 if (auto g = symbolTable->lookup<fir::GlobalOp>(name)) {
4216 #ifdef EXPENSIVE_CHECKS
4217 assert(g == module.lookupSymbol<fir::GlobalOp>(name) &&
4218 "symbolTable and module out of sync");
4219 #endif
4220 return g;
4222 if (auto g = module.lookupSymbol<fir::GlobalOp>(name))
4223 return g;
4224 mlir::OpBuilder modBuilder(module.getBodyRegion());
4225 auto result = modBuilder.create<fir::GlobalOp>(loc, name, type, attrs);
4226 result.setVisibility(mlir::SymbolTable::Visibility::Private);
4227 return result;
4230 bool fir::hasHostAssociationArgument(mlir::func::FuncOp func) {
4231 if (auto allArgAttrs = func.getAllArgAttrs())
4232 for (auto attr : allArgAttrs)
4233 if (auto dict = mlir::dyn_cast_or_null<mlir::DictionaryAttr>(attr))
4234 if (dict.get(fir::getHostAssocAttrName()))
4235 return true;
4236 return false;
4239 // Test if value's definition has the specified set of
4240 // attributeNames. The value's definition is one of the operations
4241 // that are able to carry the Fortran variable attributes, e.g.
4242 // fir.alloca or fir.allocmem. Function arguments may also represent
4243 // value definitions and carry relevant attributes.
4245 // If it is not possible to reach the limited set of definition
4246 // entities from the given value, then the function will return
4247 // std::nullopt. Otherwise, the definition is known and the return
4248 // value is computed as:
4249 // * if checkAny is true, then the function will return true
4250 // iff any of the attributeNames attributes is set on the definition.
4251 // * if checkAny is false, then the function will return true
4252 // iff all of the attributeNames attributes are set on the definition.
4253 static std::optional<bool>
4254 valueCheckFirAttributes(mlir::Value value,
4255 llvm::ArrayRef<llvm::StringRef> attributeNames,
4256 bool checkAny) {
4257 auto testAttributeSets = [&](llvm::ArrayRef<mlir::NamedAttribute> setAttrs,
4258 llvm::ArrayRef<llvm::StringRef> checkAttrs) {
4259 if (checkAny) {
4260 // Return true iff any of checkAttrs attributes is present
4261 // in setAttrs set.
4262 for (llvm::StringRef checkAttrName : checkAttrs)
4263 if (llvm::any_of(setAttrs, [&](mlir::NamedAttribute setAttr) {
4264 return setAttr.getName() == checkAttrName;
4266 return true;
4268 return false;
4271 // Return true iff all attributes from checkAttrs are present
4272 // in setAttrs set.
4273 for (mlir::StringRef checkAttrName : checkAttrs)
4274 if (llvm::none_of(setAttrs, [&](mlir::NamedAttribute setAttr) {
4275 return setAttr.getName() == checkAttrName;
4277 return false;
4279 return true;
4281 // If this is a fir.box that was loaded, the fir attributes will be on the
4282 // related fir.ref<fir.box> creation.
4283 if (mlir::isa<fir::BoxType>(value.getType()))
4284 if (auto definingOp = value.getDefiningOp())
4285 if (auto loadOp = mlir::dyn_cast<fir::LoadOp>(definingOp))
4286 value = loadOp.getMemref();
4287 // If this is a function argument, look in the argument attributes.
4288 if (auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(value)) {
4289 if (blockArg.getOwner() && blockArg.getOwner()->isEntryBlock())
4290 if (auto funcOp = mlir::dyn_cast<mlir::func::FuncOp>(
4291 blockArg.getOwner()->getParentOp()))
4292 return testAttributeSets(
4293 mlir::cast<mlir::FunctionOpInterface>(*funcOp).getArgAttrs(
4294 blockArg.getArgNumber()),
4295 attributeNames);
4297 // If it is not a function argument, the attributes are unknown.
4298 return std::nullopt;
4301 if (auto definingOp = value.getDefiningOp()) {
4302 // If this is an allocated value, look at the allocation attributes.
4303 if (mlir::isa<fir::AllocMemOp>(definingOp) ||
4304 mlir::isa<fir::AllocaOp>(definingOp))
4305 return testAttributeSets(definingOp->getAttrs(), attributeNames);
4306 // If this is an imported global, look at AddrOfOp and GlobalOp attributes.
4307 // Both operations are looked at because use/host associated variable (the
4308 // AddrOfOp) can have ASYNCHRONOUS/VOLATILE attributes even if the ultimate
4309 // entity (the globalOp) does not have them.
4310 if (auto addressOfOp = mlir::dyn_cast<fir::AddrOfOp>(definingOp)) {
4311 if (testAttributeSets(addressOfOp->getAttrs(), attributeNames))
4312 return true;
4313 if (auto module = definingOp->getParentOfType<mlir::ModuleOp>())
4314 if (auto globalOp =
4315 module.lookupSymbol<fir::GlobalOp>(addressOfOp.getSymbol()))
4316 return testAttributeSets(globalOp->getAttrs(), attributeNames);
4319 // TODO: Construct associated entities attributes. Decide where the fir
4320 // attributes must be placed/looked for in this case.
4321 return std::nullopt;
4324 bool fir::valueMayHaveFirAttributes(
4325 mlir::Value value, llvm::ArrayRef<llvm::StringRef> attributeNames) {
4326 std::optional<bool> mayHaveAttr =
4327 valueCheckFirAttributes(value, attributeNames, /*checkAny=*/true);
4328 return mayHaveAttr.value_or(true);
4331 bool fir::valueHasFirAttribute(mlir::Value value,
4332 llvm::StringRef attributeName) {
4333 std::optional<bool> mayHaveAttr =
4334 valueCheckFirAttributes(value, {attributeName}, /*checkAny=*/false);
4335 return mayHaveAttr.value_or(false);
4338 bool fir::anyFuncArgsHaveAttr(mlir::func::FuncOp func, llvm::StringRef attr) {
4339 for (unsigned i = 0, end = func.getNumArguments(); i < end; ++i)
4340 if (func.getArgAttr(i, attr))
4341 return true;
4342 return false;
4345 std::optional<std::int64_t> fir::getIntIfConstant(mlir::Value value) {
4346 if (auto *definingOp = value.getDefiningOp()) {
4347 if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
4348 if (auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(cst.getValue()))
4349 return intAttr.getInt();
4350 if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(definingOp))
4351 if (auto attr = mlir::dyn_cast<mlir::IntegerAttr>(llConstOp.getValue()))
4352 return attr.getValue().getSExtValue();
4354 return {};
4357 bool fir::isDummyArgument(mlir::Value v) {
4358 auto blockArg{mlir::dyn_cast<mlir::BlockArgument>(v)};
4359 if (!blockArg) {
4360 auto defOp = v.getDefiningOp();
4361 if (defOp) {
4362 if (auto declareOp = mlir::dyn_cast<fir::DeclareOp>(defOp))
4363 if (declareOp.getDummyScope())
4364 return true;
4366 return false;
4369 auto *owner{blockArg.getOwner()};
4370 return owner->isEntryBlock() &&
4371 mlir::isa<mlir::FunctionOpInterface>(owner->getParentOp());
4374 mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {
4375 for (auto i = path.begin(), end = path.end(); eleTy && i < end;) {
4376 eleTy = llvm::TypeSwitch<mlir::Type, mlir::Type>(eleTy)
4377 .Case<fir::RecordType>([&](fir::RecordType ty) {
4378 if (auto *op = (*i++).getDefiningOp()) {
4379 if (auto off = mlir::dyn_cast<fir::FieldIndexOp>(op))
4380 return ty.getType(off.getFieldName());
4381 if (auto off = mlir::dyn_cast<mlir::arith::ConstantOp>(op))
4382 return ty.getType(fir::toInt(off));
4384 return mlir::Type{};
4386 .Case<fir::SequenceType>([&](fir::SequenceType ty) {
4387 bool valid = true;
4388 const auto rank = ty.getDimension();
4389 for (std::remove_const_t<decltype(rank)> ii = 0;
4390 valid && ii < rank; ++ii)
4391 valid = i < end && fir::isa_integer((*i++).getType());
4392 return valid ? ty.getEleTy() : mlir::Type{};
4394 .Case<mlir::TupleType>([&](mlir::TupleType ty) {
4395 if (auto *op = (*i++).getDefiningOp())
4396 if (auto off = mlir::dyn_cast<mlir::arith::ConstantOp>(op))
4397 return ty.getType(fir::toInt(off));
4398 return mlir::Type{};
4400 .Case<mlir::ComplexType>([&](mlir::ComplexType ty) {
4401 if (fir::isa_integer((*i++).getType()))
4402 return ty.getElementType();
4403 return mlir::Type{};
4405 .Default([&](const auto &) { return mlir::Type{}; });
4407 return eleTy;
4410 llvm::LogicalResult fir::DeclareOp::verify() {
4411 auto fortranVar =
4412 mlir::cast<fir::FortranVariableOpInterface>(this->getOperation());
4413 return fortranVar.verifyDeclareLikeOpImpl(getMemref());
4416 //===----------------------------------------------------------------------===//
4417 // FIROpsDialect
4418 //===----------------------------------------------------------------------===//
4420 void fir::FIROpsDialect::registerOpExternalInterfaces() {
4421 // Attach default declare target interfaces to operations which can be marked
4422 // as declare target.
4423 fir::GlobalOp::attachInterface<
4424 mlir::omp::DeclareTargetDefaultModel<fir::GlobalOp>>(*getContext());
4427 // Tablegen operators
4429 #define GET_OP_CLASSES
4430 #include "flang/Optimizer/Dialect/FIROps.cpp.inc"