1 //===-- FIROps.cpp --------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
37 #include "flang/Optimizer/Dialect/CanonicalizationPatterns.inc"
40 static void propagateAttributes(mlir::Operation
*fromOp
,
41 mlir::Operation
*toOp
) {
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
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)
64 for (std::size_t i
= 0, end
= shape
.size(); i
< end
; ++i
) {
65 if (shape
[i
] != fir::SequenceType::getUnknownExtent())
67 if (dynamicExtents
-- == 0)
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()))
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
))
84 static bool verifyTypeParamCount(mlir::Type inType
, unsigned numParams
) {
85 auto ty
= fir::unwrapSequenceType(inType
);
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());
93 if (auto chrTy
= mlir::dyn_cast
<fir::CharacterType
>(ty
))
94 return !chrTy
.hasConstantLen();
98 /// Parser shared by Alloca and Allocmem
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
) {
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();
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
);
136 parser
.resolveOperands(operands
, typeVec
, parser
.getNameLoc(),
138 return mlir::failure();
139 mlir::Type restype
= wrapResultType(intype
);
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()
159 // print the shape of the allocation (if any); all must be index type
160 for (auto sh
: op
.getShape()) {
164 p
.printOptionalAttrDict(op
->getAttrs(), {"in_type", "operandSegmentSizes"});
167 //===----------------------------------------------------------------------===//
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
))
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
) {
215 uniqName
.empty() ? mlir::StringAttr
{} : builder
.getStringAttr(uniqName
);
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
) {
230 uniqName
.empty() ? mlir::StringAttr
{} : builder
.getStringAttr(uniqName
);
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
,
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())
292 if (fir::AllocaOp::ownsNestedAlloca(parentOp
))
293 return currentOp
->getParentRegion();
294 currentOp
= parentOp
;
299 //===----------------------------------------------------------------------===//
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
))
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
, {},
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
, {}, {},
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 //===----------------------------------------------------------------------===//
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
);
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();
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
;
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
;
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();
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();
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.
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,
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()) {
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
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
539 // %shape = fir.shape <extents from the %shapeshift>
540 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
541 boxedShape
= getShapeFromShapeShift(boxedShape
, rewriter
);
543 return mlir::failure();
545 return mlir::failure();
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();
577 return mlir::failure();
580 } else { // !op.getSlice()
582 if (boxedShapeIsShift
) {
583 // %0 = fir.rebox %arg(%shift)
584 // %1 = fir.array_coor %0 %idx
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
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
597 // %shape = fir.shape <extents from the %shapeshift>
598 // %1 = fir.array_coor %arg(%shape) %idx
599 boxedShape
= getShapeFromShapeShift(boxedShape
, rewriter
);
601 return mlir::failure();
603 return mlir::failure();
606 if (boxedShapeIsShift
) {
607 // %0 = fir.embox %arg(%shift) [%slice]
608 // %1 = fir.array_coor %0 %idx
610 // %tmp = arith.addi %idx, %shift.origin
611 // %idx_shifted = arith.subi %tmp, 1
612 // %1 = fir.array_coor %arg(%shift) %[slice] %idx_shifted
614 getShiftedIndices(boxedShape
, op
.getIndices(), rewriter
);
616 return mlir::failure();
617 } else if (boxedShapeIsShape
) {
618 // %0 = fir.embox %arg(%shape) [%slice]
619 // %1 = fir.array_coor %0 %idx
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
626 // %tmp = arith.addi %idx, %shapeshift.lb
627 // %idx_shifted = arith.subi %tmp, 1
628 // %1 = fir.array_coor %arg(%shapeshift) %[slice] %idx_shifted
630 getShiftedIndices(boxedShape
, op
.getIndices(), rewriter
);
632 return mlir::failure();
634 return mlir::failure();
638 } else { // !boxedShape
641 // %0 = fir.rebox %arg
642 // %1 = fir.array_coor %0 [%slice] %idx
644 // %1 = fir.array_coor %arg [%slice] %idx
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.
651 // %1 = fir.array_coor %arg [%slice] %idx
653 } else { // !op.getSlice()
655 // %0 = fir.rebox %arg
656 // %1 = fir.array_coor %0 %idx
658 // %1 = fir.array_coor %arg %idx
660 // %0 = fir.rebox %arg [%slice]
661 // %1 = fir.array_coor %0 %idx
663 // %1 = fir.array_coor %arg [%slice] %idx
667 } else { // op.getShape()
669 // Check if pulling in non-default shape is correct.
672 // %0 = fir.embox %arg(%shape)
673 // %1 = fir.array_coor %0(%shape) [%slice] %idx
675 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
677 // %0 = fir.embox %arg(%shape) [%slice]
678 // %1 = fir.array_coor %0(%shape) [%slice] %idx
680 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
682 } else { // !op.getSlice()
684 // %0 = fir.embox %arg(%shape)
685 // %1 = fir.array_coor %0(%shape) %idx
687 // %1 = fir.array_coor %arg(%shape) %idx
689 // %0 = fir.embox %arg(%shape) [%slice]
690 // %1 = fir.array_coor %0(%shape) %idx
692 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
695 } else { // !boxedShape
698 // %0 = fir.rebox %arg
699 // %1 = fir.array_coor %0(%shape) [%slice] %idx
701 // %1 = fir.array_coor %arg(%shape) [%slice] %idx
703 // %0 = fir.rebox %arg [%slice]
704 // %1 = fir.array_coor %0(%shape) [%slice] %idx
705 return mlir::failure();
707 } else { // !op.getSlice()
709 // %0 = fir.rebox %arg
710 // %1 = fir.array_coor %0(%shape) %idx
712 // %1 = fir.array_coor %arg(%shape) %idx
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())) {
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
);
739 op
.getShapeMutable().assign(boxedShape
);
741 op
.getSliceMutable().assign(boxedSlice
);
743 op
.getIndicesMutable().assign(*shiftedIndices
);
745 return mlir::success();
749 using IndicesVectorTy
= std::vector
<mlir::Value
>;
751 // If v is a shape_shift operation:
752 // fir.shape_shift %l1, %e1, %l2, %e2, ...
754 // fir.shape %e1, %e2, ...
755 static mlir::Value
getShapeFromShapeShift(mlir::Value v
,
756 mlir::PatternRewriter
&rewriter
) {
758 mlir::dyn_cast_or_null
<fir::ShapeShiftOp
>(v
.getDefiningOp());
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
);
788 rewriter
.create
<mlir::arith::AddIOp
>(loc
, extIdx
, extLb
, nsw
);
790 rewriter
.create
<mlir::arith::SubIOp
>(loc
, add
, one
, nsw
);
791 shiftedIndices
.push_back(sub
);
794 return shiftedIndices
;
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());
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 //===----------------------------------------------------------------------===//
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
))
825 if (fir::isa_derived(eleTy
))
827 if (mlir::isa
<fir::SequenceType
>(eleTy
))
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();
845 llvm::LogicalResult
fir::ArrayLoadOp::verify() {
846 auto eleTy
= fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
847 auto arrTy
= mlir::dyn_cast
<fir::SequenceType
>(eleTy
);
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();
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 //===----------------------------------------------------------------------===//
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()) {
893 mlir::dyn_cast_or_null
<fir::SliceOp
>(sl
.getDefiningOp())) {
894 if (!sliceOp
.getSubstr().empty())
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
)) {
903 fir::applyPathToType(seqTy
.getEleTy(), sliceOp
.getFields());
904 if (fir::unwrapSequenceType(getOriginal().getType()) != projTy
)
906 "type of origin does not match sliced memref type");
907 if (fir::unwrapSequenceType(getSequence().getType()) != projTy
)
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
1012 //===----------------------------------------------------------------------===//
1014 void fir::BoxAddrOp::build(mlir::OpBuilder
&builder
,
1015 mlir::OperationState
&result
, mlir::Value val
) {
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
))
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();
1050 //===----------------------------------------------------------------------===//
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();
1062 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
1076 //===----------------------------------------------------------------------===//
1078 void fir::BoxRankOp::getEffects(
1079 llvm::SmallVectorImpl
<
1080 mlir::SideEffects::EffectInstance
<mlir::MemoryEffects::Effect
>>
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 //===----------------------------------------------------------------------===//
1090 //===----------------------------------------------------------------------===//
1092 mlir::FunctionType
fir::CallOp::getFunctionType() {
1093 return mlir::FunctionType::get(getContext(), getOperandTypes(),
1097 void fir::CallOp::print(mlir::OpAsmPrinter
&p
) {
1098 bool isDirect
= getCallee().has_value();
1104 p
<< '(' << (*this)->getOperands().drop_front(isDirect
? 0 : 1) << ')';
1106 // Print `proc_attrs<...>`, if present.
1107 fir::FortranProcedureFlagsEnumAttr procAttrs
= getProcedureAttrsAttr();
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();
1141 if (parser
.parseAttribute(funcAttr
, fir::CallOp::getCalleeAttrNameStr(),
1143 return mlir::failure();
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
),
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
);
1172 return parser
.emitError(parser
.getNameLoc(), "expected function type");
1174 if (parser
.resolveOperands(operands
, funcType
.getInputs(),
1175 parser
.getNameLoc(), result
.operands
))
1176 return mlir::failure();
1179 llvm::ArrayRef
<mlir::OpAsmParser::UnresolvedOperand
>(operands
)
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
);
1204 result
.addAttribute(getCalleeAttrNameStr(), callee
);
1205 result
.addTypes(results
);
1208 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
1228 //===----------------------------------------------------------------------===//
1230 template <typename OPTY
>
1231 static void printCmpOp(mlir::OpAsmPrinter
&p
, OPTY op
) {
1233 auto predSym
= mlir::arith::symbolizeCmpFPredicate(
1234 op
->template getAttrOfType
<mlir::IntegerAttr
>(
1235 OPTY::getPredicateAttrName())
1237 assert(predSym
.has_value() && "invalid symbol value for predicate");
1238 p
<< '"' << mlir::arith::stringifyCmpFPredicate(predSym
.value()) << '"'
1240 p
.printOperand(op
.getLhs());
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
;
1255 if (parser
.parseAttribute(predicateNameAttr
, OPTY::getPredicateAttrName(),
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 //===----------------------------------------------------------------------===//
1281 //===----------------------------------------------------------------------===//
1283 void fir::buildCmpCOp(mlir::OpBuilder
&builder
, mlir::OperationState
&result
,
1284 mlir::arith::CmpFPredicate predicate
, mlir::Value lhs
,
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 //===----------------------------------------------------------------------===//
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())
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()))
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()))
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();
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
) {
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();
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());
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
)))
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())
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())
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
)
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 //===----------------------------------------------------------------------===//
1453 //===----------------------------------------------------------------------===//
1455 void fir::CoordinateOp::print(mlir::OpAsmPrinter
&p
) {
1456 p
<< ' ' << getRef() << ", " << getCoor();
1457 p
.printOptionalAttrDict((*this)->getAttrs(), /*elideAttrs=*/{"baseType"});
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
,
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();
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())
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());
1531 return emitOpError("field_index not applied to !fir.type");
1535 if (--dimension
== 0)
1536 eleTy
= mlir::cast
<fir::SequenceType
>(eleTy
).getElementType();
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");
1555 return emitOpError("invalid parameters (too many)");
1559 return mlir::success();
1562 //===----------------------------------------------------------------------===//
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))
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(),
1585 //===----------------------------------------------------------------------===//
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
) {
1595 result
.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
1596 builder
.getStringAttr(type
.getName()));
1597 result
.addAttribute(getTypeAttrName(result
.name
), mlir::TypeAttr::get(type
));
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 //===----------------------------------------------------------------------===//
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();
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");
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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
) {
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 //===----------------------------------------------------------------------===//
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
),
1738 // Parse the name as a symbol reference attribute.
1739 mlir::SymbolRefAttr nameAttr
;
1740 if (parser
.parseAttribute(nameAttr
,
1741 fir::GlobalOp::getSymrefAttrName(result
.name
),
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();
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
) {
1780 // Parse the optional initializer body.
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
) {
1791 p
<< ' ' << *getLinkName();
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();
1807 p
.printType(getType());
1808 if (hasInitializationBody()) {
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
) {
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
));
1832 result
.addAttribute(getConstantAttrName(result
.name
),
1833 builder
.getUnitAttr());
1835 result
.addAttribute(getTargetAttrName(result
.name
), builder
.getUnitAttr());
1837 result
.addAttribute(getInitValAttrName(result
.name
), initialVal
);
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
{},
1876 void fir::GlobalOp::build(mlir::OpBuilder
&builder
,
1877 mlir::OperationState
&result
, llvm::StringRef name
,
1879 llvm::ArrayRef
<mlir::NamedAttribute
> attrs
) {
1880 build(builder
, result
, name
, /*isConstant=*/false, /*isTarget=*/false, type
,
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 //===----------------------------------------------------------------------===//
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(),
1903 return mlir::failure();
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(),
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 //===----------------------------------------------------------------------===//
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();
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
) {
1963 << op
.getOperation()
1964 ->template getAttrOfType
<mlir::StringAttr
>(
1965 fir::FieldIndexOp::getFieldAttrName())
1967 << ", " << op
.getOperation()->getAttr(fir::FieldIndexOp::getTypeAttrName());
1968 if (op
.getNumOperands()) {
1970 p
.printOperands(op
.getTypeparams());
1972 for (auto op
: op
.getTypeparams()) {
1975 p
.printType(op
.getType());
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());
2003 //===----------------------------------------------------------------------===//
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(
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(
2046 [](auto indexed_value
) { return indexed_value
.index() % 2 != 0; }),
2047 printer
, [&](auto indexed_value
) { printer
<< indexed_value
.value(); });
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();
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
)
2069 return emitOpError("empty range");
2070 rangeIsKnownToBeNonempty
= lb
< ub
;
2072 return mlir::success();
2075 //===----------------------------------------------------------------------===//
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
;
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
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
) {}
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());
2104 return mlir::failure();
2105 auto binf
= mlir::dyn_cast_or_null
<FltOp
>(insval
.getVal().getDefiningOp());
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 //===----------------------------------------------------------------------===//
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();
2217 result
.addTypes(regionTypes
);
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;
2234 result
.addTypes(i1Type
);
2237 if (parser
.parseOptionalAttrDictWithKeyword(result
.attributes
))
2238 return mlir::failure();
2240 llvm::SmallVector
<mlir::Type
> argTypes
;
2241 // Induction variable (hidden)
2243 result
.addAttribute(IterWhileOp::getFinalValueAttrNameStr(),
2244 builder
.getUnitAttr());
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
2269 auto *body
= getBody();
2270 if (!body
->getArgument(1).getType().isInteger(1))
2272 "expected body second argument to be an index argument for "
2273 "the induction variable");
2274 if (!body
->getArgument(0).getType().isIndex())
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");
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
)
2297 "mismatch in number of loop-carried values and defined values");
2298 if (getNumRegionIterArgs() != opNumResults
)
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();
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";
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) {
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
); });
2331 llvm::interleaveComma(
2332 llvm::drop_begin(getResultTypes(), getFinalValue() ? 0 : 1), p
);
2334 } else if (getFinalValue()) {
2335 p
<< " -> (" << getResultTypes() << ')';
2337 p
.printOptionalAttrDictWithKeyword((*this)->getAttrs(),
2338 {getFinalValueAttrNameStr()});
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);
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];
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 //===----------------------------------------------------------------------===//
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());
2405 //===----------------------------------------------------------------------===//
2407 //===----------------------------------------------------------------------===//
2409 void fir::LoadOp::build(mlir::OpBuilder
&builder
, mlir::OperationState
&result
,
2410 mlir::Value refVal
) {
2412 mlir::emitError(result
.location
, "LoadOp has null argument");
2415 auto eleTy
= fir::dyn_cast_ptrEleTy(refVal
.getType());
2417 mlir::emitError(result
.location
, "not a memory reference type");
2420 build(builder
, result
, eleTy
, refVal
);
2423 void fir::LoadOp::build(mlir::OpBuilder
&builder
, mlir::OperationState
&result
,
2424 mlir::Type resTy
, mlir::Value refVal
) {
2427 mlir::emitError(result
.location
, "LoadOp has null argument");
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
) {
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();
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
) {
2458 p
.printOperand(getMemref());
2459 p
.printOptionalAttrDict(getOperation()->getAttrs(), {});
2460 p
<< " : " << getMemref().getType();
2463 //===----------------------------------------------------------------------===//
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
));
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();
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(),
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.
2593 result
.addAttribute(DoLoopOp::getFinalValueAttrName(result
.name
),
2594 builder
.getUnitAttr());
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
);
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
2629 auto *body
= getBody();
2630 if (!body
->getArgument(0).getType().isIndex())
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()) {
2641 return emitOpError("unordered loop has no final value");
2644 if (getNumIterOperands() != opNumResults
)
2646 "mismatch in number of loop-carried values and defined values");
2647 if (getNumRegionIterArgs() != opNumResults
)
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();
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";
2664 auto reduceAttrs
= getReduceAttrsAttr();
2665 if (getNumReduceOperands() != (reduceAttrs
? reduceAttrs
.size() : 0))
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();
2677 if (hasReduceOperands()) {
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();
2686 printBlockTerminators
= true;
2688 if (hasIterOperands()) {
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"});
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);
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];
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 //===----------------------------------------------------------------------===//
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
),
2759 return mlir::failure();
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(),
2768 return mlir::failure();
2769 return mlir::success();
2772 void fir::DTEntryOp::print(mlir::OpAsmPrinter
&p
) {
2773 p
<< ' ' << getMethodAttr() << ", " << getProcAttr();
2776 //===----------------------------------------------------------------------===//
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();
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
);
2796 if (c1
.hasDynamicLen() || c2
.hasDynamicLen())
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()) {
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");
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");
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();
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
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
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
)
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
)
2885 // Output is unlimited polymorphic -> output dynamic type is the same as input
2887 if (mlir::isa
<mlir::NoneType
>(outEleTy
))
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
))
2894 if (areCompatibleCharacterTypes(inputEleTy
, outEleTy
))
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
))
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
>>
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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())
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();
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();
2975 if (shapeTyRank
!= 0)
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 "
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");
3013 op
->template getAttrOfType
<mlir::ArrayAttr
>(op
.getCasesAttr()).getValue();
3014 auto count
= op
.getNumDest();
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
;
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
;
3040 mlir::Attribute ivalue
; // Integer or Unit
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())
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
);
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
) {
3076 p
.printOperand(op
.getSelector());
3077 p
<< " : " << op
.getSelector().getType() << " [";
3079 op
->template getAttrOfType
<mlir::ArrayAttr
>(op
.getCasesAttr()).getValue();
3080 auto count
= op
.getNumConditions();
3081 for (decltype(count
) i
= 0; i
!= count
; ++i
) {
3084 auto &attr
= cases
[i
];
3085 if (auto intAttr
= mlir::dyn_cast_or_null
<mlir::IntegerAttr
>(attr
))
3086 p
<< intAttr
.getValue();
3088 p
.printAttribute(attr
);
3090 op
.printSuccessorAtIndex(p
, i
);
3093 p
.printOptionalAttrDict(
3094 op
->getAttrs(), {op
.getCasesAttr(), getCompareOffsetAttr(),
3095 getTargetOffsetAttr(), op
.getOperandSegmentSizeAttr()});
3098 //===----------------------------------------------------------------------===//
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
) {
3120 for (unsigned i
= 0; i
< pos
; ++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(
3134 mlir::cast
<mlir::DenseI32ArrayAttr
>(targetOffsetAttr
.getValue()),
3135 mlir::MutableOperandRange::OperandSegment(pos
, targetOffsetAttr
));
3138 std::optional
<mlir::OperandRange
> fir::SelectOp::getCompareOperands(unsigned) {
3142 std::optional
<llvm::ArrayRef
<mlir::Value
>>
3143 fir::SelectOp::getCompareOperands(llvm::ArrayRef
<mlir::Value
>, unsigned) {
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
,
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
) {
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() {
3173 ->getAttrOfType
<mlir::DenseI32ArrayAttr
>(getTargetOffsetAttr())
3177 //===----------------------------------------------------------------------===//
3179 //===----------------------------------------------------------------------===//
3181 std::optional
<mlir::OperandRange
>
3182 fir::SelectCaseOp::getCompareOperands(unsigned cond
) {
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
,
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
,
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
,
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
,
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
;
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;
3248 mlir::Attribute attr
;
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);
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);
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()))
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
) {
3311 p
.printOperand(getSelector());
3312 p
<< " : " << getSelector().getType() << " [";
3314 getOperation()->getAttrOfType
<mlir::ArrayAttr
>(getCasesAttr()).getValue();
3315 auto count
= getNumConditions();
3316 for (decltype(count
) i
= 0; i
!= count
; ++i
) {
3319 p
<< cases
[i
] << ", ";
3320 if (!mlir::isa
<mlir::UnitAttr
>(cases
[i
])) {
3321 auto caseArgs
= *getCompareOperands(i
);
3322 p
.printOperand(*caseArgs
.begin());
3324 if (mlir::isa
<fir::ClosedIntervalAttr
>(cases
[i
])) {
3325 p
.printOperand(*(++caseArgs
.begin()));
3329 printSuccessorAtIndex(p
, i
);
3332 p
.printOptionalAttrDict(getOperation()->getAttrs(),
3333 {getCasesAttr(), getCompareOffsetAttr(),
3334 getTargetOffsetAttr(), getOperandSegmentSizeAttr()});
3337 unsigned fir::SelectCaseOp::compareOffsetSize() {
3339 ->getAttrOfType
<mlir::DenseI32ArrayAttr
>(getCompareOffsetAttr())
3343 unsigned fir::SelectCaseOp::targetOffsetSize() {
3345 ->getAttrOfType
<mlir::DenseI32ArrayAttr
>(getTargetOffsetAttr())
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);
3365 } else if (mlir::isa
<mlir::UnitAttr
>(attr
)) {
3366 operOffs
.push_back(0);
3368 operOffs
.push_back(1);
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
) {
3384 result
.addOperands(destOperands
[i
]);
3385 const auto argSz
= destOperands
[i
].size();
3386 argOffs
.push_back(argSz
);
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}));
3417 } else if (mlir::isa
<mlir::UnitAttr
>(attr
)) {
3418 cmpOpers
.push_back(mlir::ValueRange
{});
3420 cmpOpers
.push_back(mlir::ValueRange({iter
, iter
+ 1}));
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");
3433 getOperation()->getAttrOfType
<mlir::ArrayAttr
>(getCasesAttr()).getValue();
3434 auto count
= getNumDest();
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 //===----------------------------------------------------------------------===//
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) {
3478 std::optional
<llvm::ArrayRef
<mlir::Value
>>
3479 fir::SelectRankOp::getCompareOperands(llvm::ArrayRef
<mlir::Value
>, unsigned) {
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
,
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
,
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() {
3510 ->getAttrOfType
<mlir::DenseI32ArrayAttr
>(getTargetOffsetAttr())
3514 //===----------------------------------------------------------------------===//
3516 //===----------------------------------------------------------------------===//
3518 std::optional
<mlir::OperandRange
>
3519 fir::SelectTypeOp::getCompareOperands(unsigned) {
3523 std::optional
<llvm::ArrayRef
<mlir::Value
>>
3524 fir::SelectTypeOp::getCompareOperands(llvm::ArrayRef
<mlir::Value
>, unsigned) {
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
,
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
,
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
;
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
;
3564 mlir::Attribute attr
;
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()))
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
);
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() {
3600 ->getAttrOfType
<mlir::DenseI32ArrayAttr
>(getTargetOffsetAttr())
3604 void fir::SelectTypeOp::print(mlir::OpAsmPrinter
&p
) {
3606 p
.printOperand(getSelector());
3607 p
<< " : " << getSelector().getType() << " [";
3609 getOperation()->getAttrOfType
<mlir::ArrayAttr
>(getCasesAttr()).getValue();
3610 auto count
= getNumConditions();
3611 for (decltype(count
) i
= 0; i
!= count
; ++i
) {
3614 p
<< cases
[i
] << ", ";
3615 printSuccessorAtIndex(p
, i
);
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();
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
>(
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
) {
3667 result
.addOperands(destOperands
[i
]);
3668 const auto argSz
= destOperands
[i
].size();
3669 argOffs
.push_back(argSz
);
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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");
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 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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
) {
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
))
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");
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 //===----------------------------------------------------------------------===//
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
) {
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
),
3790 parser
.resolveOperand(store
, type
, result
.operands
))
3791 return mlir::failure();
3792 return mlir::success();
3795 void fir::StoreOp::print(mlir::OpAsmPrinter
&p
) {
3797 p
.printOperand(getValue());
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 //===----------------------------------------------------------------------===//
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
) {
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
) {
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
) {
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
) {
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
));
3911 return parser
.emitError(parser
.getCurrentLocation(),
3912 "found an invalid constant");
3913 mlir::IntegerAttr sz
;
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
);
3922 return parser
.emitError(trailingTypeLoc
, "must have character type");
3923 type
= fir::CharacterType::get(builder
.getContext(), charTy
.getFKind(),
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
)) {
3947 return emitOpError("has unexpected attribute");
3950 return mlir::success();
3953 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
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
> ®ions
) {
4000 // The `then` and the `else` region branch back to the parent operation.
4001 if (!point
.isParent()) {
4002 regions
.push_back(mlir::RegionSuccessor(getResults()));
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());
4014 regions
.push_back(mlir::RegionSuccessor(elseRegion
));
4017 void fir::IfOp::getEntrySuccessorRegions(
4018 llvm::ArrayRef
<mlir::Attribute
> operands
,
4019 llvm::SmallVectorImpl
<mlir::RegionSuccessor
> ®ions
) {
4020 FoldAdaptor
adaptor(operands
);
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());
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);
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(),
4070 if (mlir::succeeded(parser
.parseOptionalKeyword("else"))) {
4071 if (parser
.parseRegion(*elseRegion
, {}, {}))
4072 return mlir::failure();
4073 fir::IfOp::ensureTerminator(*elseRegion
, parser
.getBuilder(),
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;
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()) {
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 //===----------------------------------------------------------------------===//
4123 //===----------------------------------------------------------------------===//
4125 llvm::LogicalResult
fir::BoxOffsetOp::verify() {
4126 auto boxType
= mlir::dyn_cast_or_null
<fir::BaseBoxType
>(
4127 fir::dyn_cast_ptrEleTy(getBoxRef().getType()));
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
,
4166 for (unsigned i
= 0; i
< dest
; ++i
) {
4167 auto &attr
= cases
[i
];
4168 if (!mlir::dyn_cast_or_null
<mlir::UnitAttr
>(attr
)) {
4170 if (mlir::dyn_cast_or_null
<fir::ClosedIntervalAttr
>(attr
))
4178 fir::parseSelector(mlir::OpAsmParser
&parser
, mlir::OperationState
&result
,
4179 mlir::OpAsmParser::UnresolvedOperand
&selector
,
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
) {
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");
4201 if (auto f
= module
.lookupSymbol
<mlir::func::FuncOp
>(name
))
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
);
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
) {
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");
4222 if (auto g
= module
.lookupSymbol
<fir::GlobalOp
>(name
))
4224 mlir::OpBuilder
modBuilder(module
.getBodyRegion());
4225 auto result
= modBuilder
.create
<fir::GlobalOp
>(loc
, name
, type
, attrs
);
4226 result
.setVisibility(mlir::SymbolTable::Visibility::Private
);
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()))
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
,
4257 auto testAttributeSets
= [&](llvm::ArrayRef
<mlir::NamedAttribute
> setAttrs
,
4258 llvm::ArrayRef
<llvm::StringRef
> checkAttrs
) {
4260 // Return true iff any of checkAttrs attributes is present
4262 for (llvm::StringRef checkAttrName
: checkAttrs
)
4263 if (llvm::any_of(setAttrs
, [&](mlir::NamedAttribute setAttr
) {
4264 return setAttr
.getName() == checkAttrName
;
4271 // Return true iff all attributes from checkAttrs are present
4273 for (mlir::StringRef checkAttrName
: checkAttrs
)
4274 if (llvm::none_of(setAttrs
, [&](mlir::NamedAttribute setAttr
) {
4275 return setAttr
.getName() == checkAttrName
;
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()),
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
))
4313 if (auto module
= definingOp
->getParentOfType
<mlir::ModuleOp
>())
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
))
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();
4357 bool fir::isDummyArgument(mlir::Value v
) {
4358 auto blockArg
{mlir::dyn_cast
<mlir::BlockArgument
>(v
)};
4360 auto defOp
= v
.getDefiningOp();
4362 if (auto declareOp
= mlir::dyn_cast
<fir::DeclareOp
>(defOp
))
4363 if (declareOp
.getDummyScope())
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
) {
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
{}; });
4410 llvm::LogicalResult
fir::DeclareOp::verify() {
4412 mlir::cast
<fir::FortranVariableOpInterface
>(this->getOperation());
4413 return fortranVar
.verifyDeclareLikeOpImpl(getMemref());
4416 //===----------------------------------------------------------------------===//
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"