1 //===-- FIROps.cpp --------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "flang/Optimizer/Dialect/FIROps.h"
14 #include "flang/Optimizer/Dialect/FIRAttr.h"
15 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
16 #include "flang/Optimizer/Dialect/FIRType.h"
17 #include "flang/Optimizer/Support/FIRContext.h"
18 #include "flang/Optimizer/Support/KindMapping.h"
19 #include "flang/Optimizer/Support/Utils.h"
20 #include "mlir/Dialect/CommonFolders.h"
21 #include "mlir/Dialect/Func/IR/FuncOps.h"
22 #include "mlir/IR/BuiltinAttributes.h"
23 #include "mlir/IR/BuiltinOps.h"
24 #include "mlir/IR/Diagnostics.h"
25 #include "mlir/IR/Matchers.h"
26 #include "mlir/IR/OpDefinition.h"
27 #include "mlir/IR/PatternMatch.h"
28 #include "llvm/ADT/STLExtras.h"
29 #include "llvm/ADT/SmallVector.h"
30 #include "llvm/ADT/StringSwitch.h"
31 #include "llvm/ADT/TypeSwitch.h"
32 
33 namespace {
34 #include "flang/Optimizer/Dialect/CanonicalizationPatterns.inc"
35 } // namespace
36 
37 /// Return true if a sequence type is of some incomplete size or a record type
38 /// is malformed or contains an incomplete sequence type. An incomplete sequence
39 /// type is one with more unknown extents in the type than have been provided
40 /// via `dynamicExtents`. Sequence types with an unknown rank are incomplete by
41 /// definition.
42 static bool verifyInType(mlir::Type inType,
43                          llvm::SmallVectorImpl<llvm::StringRef> &visited,
44                          unsigned dynamicExtents = 0) {
45   if (auto st = inType.dyn_cast<fir::SequenceType>()) {
46     auto shape = st.getShape();
47     if (shape.size() == 0)
48       return true;
49     for (std::size_t i = 0, end = shape.size(); i < end; ++i) {
50       if (shape[i] != fir::SequenceType::getUnknownExtent())
51         continue;
52       if (dynamicExtents-- == 0)
53         return true;
54     }
55   } else if (auto rt = inType.dyn_cast<fir::RecordType>()) {
56     // don't recurse if we're already visiting this one
57     if (llvm::is_contained(visited, rt.getName()))
58       return false;
59     // keep track of record types currently being visited
60     visited.push_back(rt.getName());
61     for (auto &field : rt.getTypeList())
62       if (verifyInType(field.second, visited))
63         return true;
64     visited.pop_back();
65   }
66   return false;
67 }
68 
69 static bool verifyTypeParamCount(mlir::Type inType, unsigned numParams) {
70   auto ty = fir::unwrapSequenceType(inType);
71   if (numParams > 0) {
72     if (auto recTy = ty.dyn_cast<fir::RecordType>())
73       return numParams != recTy.getNumLenParams();
74     if (auto chrTy = ty.dyn_cast<fir::CharacterType>())
75       return !(numParams == 1 && chrTy.hasDynamicLen());
76     return true;
77   }
78   if (auto chrTy = ty.dyn_cast<fir::CharacterType>())
79     return !chrTy.hasConstantLen();
80   return false;
81 }
82 
83 /// Parser shared by Alloca and Allocmem
84 ///
85 /// operation ::= %res = (`fir.alloca` | `fir.allocmem`) $in_type
86 ///                      ( `(` $typeparams `)` )? ( `,` $shape )?
87 ///                      attr-dict-without-keyword
88 template <typename FN>
89 static mlir::ParseResult parseAllocatableOp(FN wrapResultType,
90                                             mlir::OpAsmParser &parser,
91                                             mlir::OperationState &result) {
92   mlir::Type intype;
93   if (parser.parseType(intype))
94     return mlir::failure();
95   auto &builder = parser.getBuilder();
96   result.addAttribute("in_type", mlir::TypeAttr::get(intype));
97   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
98   llvm::SmallVector<mlir::Type> typeVec;
99   bool hasOperands = false;
100   std::int32_t typeparamsSize = 0;
101   if (!parser.parseOptionalLParen()) {
102     // parse the LEN params of the derived type. (<params> : <types>)
103     if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None) ||
104         parser.parseColonTypeList(typeVec) || parser.parseRParen())
105       return mlir::failure();
106     typeparamsSize = operands.size();
107     hasOperands = true;
108   }
109   std::int32_t shapeSize = 0;
110   if (!parser.parseOptionalComma()) {
111     // parse size to scale by, vector of n dimensions of type index
112     if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None))
113       return mlir::failure();
114     shapeSize = operands.size() - typeparamsSize;
115     auto idxTy = builder.getIndexType();
116     for (std::int32_t i = typeparamsSize, end = operands.size(); i != end; ++i)
117       typeVec.push_back(idxTy);
118     hasOperands = true;
119   }
120   if (hasOperands &&
121       parser.resolveOperands(operands, typeVec, parser.getNameLoc(),
122                              result.operands))
123     return mlir::failure();
124   mlir::Type restype = wrapResultType(intype);
125   if (!restype) {
126     parser.emitError(parser.getNameLoc(), "invalid allocate type: ") << intype;
127     return mlir::failure();
128   }
129   result.addAttribute("operand_segment_sizes",
130                       builder.getI32VectorAttr({typeparamsSize, shapeSize}));
131   if (parser.parseOptionalAttrDict(result.attributes) ||
132       parser.addTypeToList(restype, result.types))
133     return mlir::failure();
134   return mlir::success();
135 }
136 
137 template <typename OP>
138 static void printAllocatableOp(mlir::OpAsmPrinter &p, OP &op) {
139   p << ' ' << op.getInType();
140   if (!op.getTypeparams().empty()) {
141     p << '(' << op.getTypeparams() << " : " << op.getTypeparams().getTypes()
142       << ')';
143   }
144   // print the shape of the allocation (if any); all must be index type
145   for (auto sh : op.getShape()) {
146     p << ", ";
147     p.printOperand(sh);
148   }
149   p.printOptionalAttrDict(op->getAttrs(), {"in_type", "operand_segment_sizes"});
150 }
151 
152 //===----------------------------------------------------------------------===//
153 // AllocaOp
154 //===----------------------------------------------------------------------===//
155 
156 /// Create a legal memory reference as return type
157 static mlir::Type wrapAllocaResultType(mlir::Type intype) {
158   // FIR semantics: memory references to memory references are disallowed
159   if (intype.isa<fir::ReferenceType>())
160     return {};
161   return fir::ReferenceType::get(intype);
162 }
163 
164 mlir::Type fir::AllocaOp::getAllocatedType() {
165   return getType().cast<fir::ReferenceType>().getEleTy();
166 }
167 
168 mlir::Type fir::AllocaOp::getRefTy(mlir::Type ty) {
169   return fir::ReferenceType::get(ty);
170 }
171 
172 void fir::AllocaOp::build(mlir::OpBuilder &builder,
173                           mlir::OperationState &result, mlir::Type inType,
174                           llvm::StringRef uniqName, mlir::ValueRange typeparams,
175                           mlir::ValueRange shape,
176                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
177   auto nameAttr = builder.getStringAttr(uniqName);
178   build(builder, result, wrapAllocaResultType(inType), inType, nameAttr, {},
179         /*pinned=*/false, typeparams, shape);
180   result.addAttributes(attributes);
181 }
182 
183 void fir::AllocaOp::build(mlir::OpBuilder &builder,
184                           mlir::OperationState &result, mlir::Type inType,
185                           llvm::StringRef uniqName, bool pinned,
186                           mlir::ValueRange typeparams, mlir::ValueRange shape,
187                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
188   auto nameAttr = builder.getStringAttr(uniqName);
189   build(builder, result, wrapAllocaResultType(inType), inType, nameAttr, {},
190         pinned, typeparams, shape);
191   result.addAttributes(attributes);
192 }
193 
194 void fir::AllocaOp::build(mlir::OpBuilder &builder,
195                           mlir::OperationState &result, mlir::Type inType,
196                           llvm::StringRef uniqName, llvm::StringRef bindcName,
197                           mlir::ValueRange typeparams, mlir::ValueRange shape,
198                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
199   auto nameAttr =
200       uniqName.empty() ? mlir::StringAttr{} : builder.getStringAttr(uniqName);
201   auto bindcAttr =
202       bindcName.empty() ? mlir::StringAttr{} : builder.getStringAttr(bindcName);
203   build(builder, result, wrapAllocaResultType(inType), inType, nameAttr,
204         bindcAttr, /*pinned=*/false, typeparams, shape);
205   result.addAttributes(attributes);
206 }
207 
208 void fir::AllocaOp::build(mlir::OpBuilder &builder,
209                           mlir::OperationState &result, mlir::Type inType,
210                           llvm::StringRef uniqName, llvm::StringRef bindcName,
211                           bool pinned, mlir::ValueRange typeparams,
212                           mlir::ValueRange shape,
213                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
214   auto nameAttr =
215       uniqName.empty() ? mlir::StringAttr{} : builder.getStringAttr(uniqName);
216   auto bindcAttr =
217       bindcName.empty() ? mlir::StringAttr{} : builder.getStringAttr(bindcName);
218   build(builder, result, wrapAllocaResultType(inType), inType, nameAttr,
219         bindcAttr, pinned, typeparams, shape);
220   result.addAttributes(attributes);
221 }
222 
223 void fir::AllocaOp::build(mlir::OpBuilder &builder,
224                           mlir::OperationState &result, mlir::Type inType,
225                           mlir::ValueRange typeparams, mlir::ValueRange shape,
226                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
227   build(builder, result, wrapAllocaResultType(inType), inType, {}, {},
228         /*pinned=*/false, typeparams, shape);
229   result.addAttributes(attributes);
230 }
231 
232 void fir::AllocaOp::build(mlir::OpBuilder &builder,
233                           mlir::OperationState &result, mlir::Type inType,
234                           bool pinned, mlir::ValueRange typeparams,
235                           mlir::ValueRange shape,
236                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
237   build(builder, result, wrapAllocaResultType(inType), inType, {}, {}, pinned,
238         typeparams, shape);
239   result.addAttributes(attributes);
240 }
241 
242 mlir::ParseResult fir::AllocaOp::parse(mlir::OpAsmParser &parser,
243                                        mlir::OperationState &result) {
244   return parseAllocatableOp(wrapAllocaResultType, parser, result);
245 }
246 
247 void fir::AllocaOp::print(mlir::OpAsmPrinter &p) {
248   printAllocatableOp(p, *this);
249 }
250 
251 mlir::LogicalResult fir::AllocaOp::verify() {
252   llvm::SmallVector<llvm::StringRef> visited;
253   if (verifyInType(getInType(), visited, numShapeOperands()))
254     return emitOpError("invalid type for allocation");
255   if (verifyTypeParamCount(getInType(), numLenParams()))
256     return emitOpError("LEN params do not correspond to type");
257   mlir::Type outType = getType();
258   if (!outType.isa<fir::ReferenceType>())
259     return emitOpError("must be a !fir.ref type");
260   if (fir::isa_unknown_size_box(fir::dyn_cast_ptrEleTy(outType)))
261     return emitOpError("cannot allocate !fir.box of unknown rank or type");
262   return mlir::success();
263 }
264 
265 //===----------------------------------------------------------------------===//
266 // AllocMemOp
267 //===----------------------------------------------------------------------===//
268 
269 /// Create a legal heap reference as return type
270 static mlir::Type wrapAllocMemResultType(mlir::Type intype) {
271   // Fortran semantics: C852 an entity cannot be both ALLOCATABLE and POINTER
272   // 8.5.3 note 1 prohibits ALLOCATABLE procedures as well
273   // FIR semantics: one may not allocate a memory reference value
274   if (intype.isa<fir::ReferenceType, fir::HeapType, fir::PointerType,
275                  mlir::FunctionType>())
276     return {};
277   return fir::HeapType::get(intype);
278 }
279 
280 mlir::Type fir::AllocMemOp::getAllocatedType() {
281   return getType().cast<fir::HeapType>().getEleTy();
282 }
283 
284 mlir::Type fir::AllocMemOp::getRefTy(mlir::Type ty) {
285   return fir::HeapType::get(ty);
286 }
287 
288 void fir::AllocMemOp::build(mlir::OpBuilder &builder,
289                             mlir::OperationState &result, mlir::Type inType,
290                             llvm::StringRef uniqName,
291                             mlir::ValueRange typeparams, mlir::ValueRange shape,
292                             llvm::ArrayRef<mlir::NamedAttribute> attributes) {
293   auto nameAttr = builder.getStringAttr(uniqName);
294   build(builder, result, wrapAllocMemResultType(inType), inType, nameAttr, {},
295         typeparams, shape);
296   result.addAttributes(attributes);
297 }
298 
299 void fir::AllocMemOp::build(mlir::OpBuilder &builder,
300                             mlir::OperationState &result, mlir::Type inType,
301                             llvm::StringRef uniqName, llvm::StringRef bindcName,
302                             mlir::ValueRange typeparams, mlir::ValueRange shape,
303                             llvm::ArrayRef<mlir::NamedAttribute> attributes) {
304   auto nameAttr = builder.getStringAttr(uniqName);
305   auto bindcAttr = builder.getStringAttr(bindcName);
306   build(builder, result, wrapAllocMemResultType(inType), inType, nameAttr,
307         bindcAttr, typeparams, shape);
308   result.addAttributes(attributes);
309 }
310 
311 void fir::AllocMemOp::build(mlir::OpBuilder &builder,
312                             mlir::OperationState &result, mlir::Type inType,
313                             mlir::ValueRange typeparams, mlir::ValueRange shape,
314                             llvm::ArrayRef<mlir::NamedAttribute> attributes) {
315   build(builder, result, wrapAllocMemResultType(inType), inType, {}, {},
316         typeparams, shape);
317   result.addAttributes(attributes);
318 }
319 
320 mlir::ParseResult fir::AllocMemOp::parse(mlir::OpAsmParser &parser,
321                                          mlir::OperationState &result) {
322   return parseAllocatableOp(wrapAllocMemResultType, parser, result);
323 }
324 
325 void fir::AllocMemOp::print(mlir::OpAsmPrinter &p) {
326   printAllocatableOp(p, *this);
327 }
328 
329 mlir::LogicalResult fir::AllocMemOp::verify() {
330   llvm::SmallVector<llvm::StringRef> visited;
331   if (verifyInType(getInType(), visited, numShapeOperands()))
332     return emitOpError("invalid type for allocation");
333   if (verifyTypeParamCount(getInType(), numLenParams()))
334     return emitOpError("LEN params do not correspond to type");
335   mlir::Type outType = getType();
336   if (!outType.dyn_cast<fir::HeapType>())
337     return emitOpError("must be a !fir.heap type");
338   if (fir::isa_unknown_size_box(fir::dyn_cast_ptrEleTy(outType)))
339     return emitOpError("cannot allocate !fir.box of unknown rank or type");
340   return mlir::success();
341 }
342 
343 //===----------------------------------------------------------------------===//
344 // ArrayCoorOp
345 //===----------------------------------------------------------------------===//
346 
347 mlir::LogicalResult fir::ArrayCoorOp::verify() {
348   auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
349   auto arrTy = eleTy.dyn_cast<fir::SequenceType>();
350   if (!arrTy)
351     return emitOpError("must be a reference to an array");
352   auto arrDim = arrTy.getDimension();
353 
354   if (auto shapeOp = getShape()) {
355     auto shapeTy = shapeOp.getType();
356     unsigned shapeTyRank = 0;
357     if (auto s = shapeTy.dyn_cast<fir::ShapeType>()) {
358       shapeTyRank = s.getRank();
359     } else if (auto ss = shapeTy.dyn_cast<fir::ShapeShiftType>()) {
360       shapeTyRank = ss.getRank();
361     } else {
362       auto s = shapeTy.cast<fir::ShiftType>();
363       shapeTyRank = s.getRank();
364       if (!getMemref().getType().isa<fir::BoxType>())
365         return emitOpError("shift can only be provided with fir.box memref");
366     }
367     if (arrDim && arrDim != shapeTyRank)
368       return emitOpError("rank of dimension mismatched");
369     if (shapeTyRank != getIndices().size())
370       return emitOpError("number of indices do not match dim rank");
371   }
372 
373   if (auto sliceOp = getSlice()) {
374     if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))
375       if (!sl.getSubstr().empty())
376         return emitOpError("array_coor cannot take a slice with substring");
377     if (auto sliceTy = sliceOp.getType().dyn_cast<fir::SliceType>())
378       if (sliceTy.getRank() != arrDim)
379         return emitOpError("rank of dimension in slice mismatched");
380   }
381 
382   return mlir::success();
383 }
384 
385 //===----------------------------------------------------------------------===//
386 // ArrayLoadOp
387 //===----------------------------------------------------------------------===//
388 
389 static mlir::Type adjustedElementType(mlir::Type t) {
390   if (auto ty = t.dyn_cast<fir::ReferenceType>()) {
391     auto eleTy = ty.getEleTy();
392     if (fir::isa_char(eleTy))
393       return eleTy;
394     if (fir::isa_derived(eleTy))
395       return eleTy;
396     if (eleTy.isa<fir::SequenceType>())
397       return eleTy;
398   }
399   return t;
400 }
401 
402 std::vector<mlir::Value> fir::ArrayLoadOp::getExtents() {
403   if (auto sh = getShape())
404     if (auto *op = sh.getDefiningOp()) {
405       if (auto shOp = mlir::dyn_cast<fir::ShapeOp>(op)) {
406         auto extents = shOp.getExtents();
407         return {extents.begin(), extents.end()};
408       }
409       return mlir::cast<fir::ShapeShiftOp>(op).getExtents();
410     }
411   return {};
412 }
413 
414 mlir::LogicalResult fir::ArrayLoadOp::verify() {
415   auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
416   auto arrTy = eleTy.dyn_cast<fir::SequenceType>();
417   if (!arrTy)
418     return emitOpError("must be a reference to an array");
419   auto arrDim = arrTy.getDimension();
420 
421   if (auto shapeOp = getShape()) {
422     auto shapeTy = shapeOp.getType();
423     unsigned shapeTyRank = 0u;
424     if (auto s = shapeTy.dyn_cast<fir::ShapeType>()) {
425       shapeTyRank = s.getRank();
426     } else if (auto ss = shapeTy.dyn_cast<fir::ShapeShiftType>()) {
427       shapeTyRank = ss.getRank();
428     } else {
429       auto s = shapeTy.cast<fir::ShiftType>();
430       shapeTyRank = s.getRank();
431       if (!getMemref().getType().isa<fir::BoxType>())
432         return emitOpError("shift can only be provided with fir.box memref");
433     }
434     if (arrDim && arrDim != shapeTyRank)
435       return emitOpError("rank of dimension mismatched");
436   }
437 
438   if (auto sliceOp = getSlice()) {
439     if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))
440       if (!sl.getSubstr().empty())
441         return emitOpError("array_load cannot take a slice with substring");
442     if (auto sliceTy = sliceOp.getType().dyn_cast<fir::SliceType>())
443       if (sliceTy.getRank() != arrDim)
444         return emitOpError("rank of dimension in slice mismatched");
445   }
446 
447   return mlir::success();
448 }
449 
450 //===----------------------------------------------------------------------===//
451 // ArrayMergeStoreOp
452 //===----------------------------------------------------------------------===//
453 
454 mlir::LogicalResult fir::ArrayMergeStoreOp::verify() {
455   if (!mlir::isa<fir::ArrayLoadOp>(getOriginal().getDefiningOp()))
456     return emitOpError("operand #0 must be result of a fir.array_load op");
457   if (auto sl = getSlice()) {
458     if (auto sliceOp =
459             mlir::dyn_cast_or_null<fir::SliceOp>(sl.getDefiningOp())) {
460       if (!sliceOp.getSubstr().empty())
461         return emitOpError(
462             "array_merge_store cannot take a slice with substring");
463       if (!sliceOp.getFields().empty()) {
464         // This is an intra-object merge, where the slice is projecting the
465         // subfields that are to be overwritten by the merge operation.
466         auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
467         if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>()) {
468           auto projTy =
469               fir::applyPathToType(seqTy.getEleTy(), sliceOp.getFields());
470           if (fir::unwrapSequenceType(getOriginal().getType()) != projTy)
471             return emitOpError(
472                 "type of origin does not match sliced memref type");
473           if (fir::unwrapSequenceType(getSequence().getType()) != projTy)
474             return emitOpError(
475                 "type of sequence does not match sliced memref type");
476           return mlir::success();
477         }
478         return emitOpError("referenced type is not an array");
479       }
480     }
481     return mlir::success();
482   }
483   auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());
484   if (getOriginal().getType() != eleTy)
485     return emitOpError("type of origin does not match memref element type");
486   if (getSequence().getType() != eleTy)
487     return emitOpError("type of sequence does not match memref element type");
488   return mlir::success();
489 }
490 
491 //===----------------------------------------------------------------------===//
492 // ArrayFetchOp
493 //===----------------------------------------------------------------------===//
494 
495 // Template function used for both array_fetch and array_update verification.
496 template <typename A>
497 mlir::Type validArraySubobject(A op) {
498   auto ty = op.getSequence().getType();
499   return fir::applyPathToType(ty, op.getIndices());
500 }
501 
502 mlir::LogicalResult fir::ArrayFetchOp::verify() {
503   auto arrTy = getSequence().getType().cast<fir::SequenceType>();
504   auto indSize = getIndices().size();
505   if (indSize < arrTy.getDimension())
506     return emitOpError("number of indices != dimension of array");
507   if (indSize == arrTy.getDimension() &&
508       ::adjustedElementType(getElement().getType()) != arrTy.getEleTy())
509     return emitOpError("return type does not match array");
510   auto ty = validArraySubobject(*this);
511   if (!ty || ty != ::adjustedElementType(getType()))
512     return emitOpError("return type and/or indices do not type check");
513   if (!mlir::isa<fir::ArrayLoadOp>(getSequence().getDefiningOp()))
514     return emitOpError("argument #0 must be result of fir.array_load");
515   return mlir::success();
516 }
517 
518 //===----------------------------------------------------------------------===//
519 // ArrayAccessOp
520 //===----------------------------------------------------------------------===//
521 
522 mlir::LogicalResult fir::ArrayAccessOp::verify() {
523   auto arrTy = getSequence().getType().cast<fir::SequenceType>();
524   std::size_t indSize = getIndices().size();
525   if (indSize < arrTy.getDimension())
526     return emitOpError("number of indices != dimension of array");
527   if (indSize == arrTy.getDimension() &&
528       getElement().getType() != fir::ReferenceType::get(arrTy.getEleTy()))
529     return emitOpError("return type does not match array");
530   mlir::Type ty = validArraySubobject(*this);
531   if (!ty || fir::ReferenceType::get(ty) != getType())
532     return emitOpError("return type and/or indices do not type check");
533   return mlir::success();
534 }
535 
536 //===----------------------------------------------------------------------===//
537 // ArrayUpdateOp
538 //===----------------------------------------------------------------------===//
539 
540 mlir::LogicalResult fir::ArrayUpdateOp::verify() {
541   if (fir::isa_ref_type(getMerge().getType()))
542     return emitOpError("does not support reference type for merge");
543   auto arrTy = getSequence().getType().cast<fir::SequenceType>();
544   auto indSize = getIndices().size();
545   if (indSize < arrTy.getDimension())
546     return emitOpError("number of indices != dimension of array");
547   if (indSize == arrTy.getDimension() &&
548       ::adjustedElementType(getMerge().getType()) != arrTy.getEleTy())
549     return emitOpError("merged value does not have element type");
550   auto ty = validArraySubobject(*this);
551   if (!ty || ty != ::adjustedElementType(getMerge().getType()))
552     return emitOpError("merged value and/or indices do not type check");
553   return mlir::success();
554 }
555 
556 //===----------------------------------------------------------------------===//
557 // ArrayModifyOp
558 //===----------------------------------------------------------------------===//
559 
560 mlir::LogicalResult fir::ArrayModifyOp::verify() {
561   auto arrTy = getSequence().getType().cast<fir::SequenceType>();
562   auto indSize = getIndices().size();
563   if (indSize < arrTy.getDimension())
564     return emitOpError("number of indices must match array dimension");
565   return mlir::success();
566 }
567 
568 //===----------------------------------------------------------------------===//
569 // BoxAddrOp
570 //===----------------------------------------------------------------------===//
571 
572 mlir::OpFoldResult fir::BoxAddrOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
573   if (auto *v = getVal().getDefiningOp()) {
574     if (auto box = mlir::dyn_cast<fir::EmboxOp>(v)) {
575       if (!box.getSlice()) // Fold only if not sliced
576         return box.getMemref();
577     }
578     if (auto box = mlir::dyn_cast<fir::EmboxCharOp>(v))
579       return box.getMemref();
580   }
581   return {};
582 }
583 
584 //===----------------------------------------------------------------------===//
585 // BoxCharLenOp
586 //===----------------------------------------------------------------------===//
587 
588 mlir::OpFoldResult
589 fir::BoxCharLenOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
590   if (auto v = getVal().getDefiningOp()) {
591     if (auto box = mlir::dyn_cast<fir::EmboxCharOp>(v))
592       return box.getLen();
593   }
594   return {};
595 }
596 
597 //===----------------------------------------------------------------------===//
598 // BoxDimsOp
599 //===----------------------------------------------------------------------===//
600 
601 /// Get the result types packed in a tuple tuple
602 mlir::Type fir::BoxDimsOp::getTupleType() {
603   // note: triple, but 4 is nearest power of 2
604   llvm::SmallVector<mlir::Type> triple{
605       getResult(0).getType(), getResult(1).getType(), getResult(2).getType()};
606   return mlir::TupleType::get(getContext(), triple);
607 }
608 
609 //===----------------------------------------------------------------------===//
610 // CallOp
611 //===----------------------------------------------------------------------===//
612 
613 mlir::FunctionType fir::CallOp::getFunctionType() {
614   return mlir::FunctionType::get(getContext(), getOperandTypes(),
615                                  getResultTypes());
616 }
617 
618 void fir::CallOp::print(mlir::OpAsmPrinter &p) {
619   bool isDirect = getCallee().has_value();
620   p << ' ';
621   if (isDirect)
622     p << *getCallee();
623   else
624     p << getOperand(0);
625   p << '(' << (*this)->getOperands().drop_front(isDirect ? 0 : 1) << ')';
626   p.printOptionalAttrDict((*this)->getAttrs(),
627                           {fir::CallOp::getCalleeAttrNameStr()});
628   auto resultTypes{getResultTypes()};
629   llvm::SmallVector<mlir::Type> argTypes(
630       llvm::drop_begin(getOperandTypes(), isDirect ? 0 : 1));
631   p << " : " << mlir::FunctionType::get(getContext(), argTypes, resultTypes);
632 }
633 
634 mlir::ParseResult fir::CallOp::parse(mlir::OpAsmParser &parser,
635                                      mlir::OperationState &result) {
636   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
637   if (parser.parseOperandList(operands))
638     return mlir::failure();
639 
640   mlir::NamedAttrList attrs;
641   mlir::SymbolRefAttr funcAttr;
642   bool isDirect = operands.empty();
643   if (isDirect)
644     if (parser.parseAttribute(funcAttr, fir::CallOp::getCalleeAttrNameStr(),
645                               attrs))
646       return mlir::failure();
647 
648   mlir::Type type;
649   if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::Paren) ||
650       parser.parseOptionalAttrDict(attrs) || parser.parseColon() ||
651       parser.parseType(type))
652     return mlir::failure();
653 
654   auto funcType = type.dyn_cast<mlir::FunctionType>();
655   if (!funcType)
656     return parser.emitError(parser.getNameLoc(), "expected function type");
657   if (isDirect) {
658     if (parser.resolveOperands(operands, funcType.getInputs(),
659                                parser.getNameLoc(), result.operands))
660       return mlir::failure();
661   } else {
662     auto funcArgs =
663         llvm::ArrayRef<mlir::OpAsmParser::UnresolvedOperand>(operands)
664             .drop_front();
665     if (parser.resolveOperand(operands[0], funcType, result.operands) ||
666         parser.resolveOperands(funcArgs, funcType.getInputs(),
667                                parser.getNameLoc(), result.operands))
668       return mlir::failure();
669   }
670   result.addTypes(funcType.getResults());
671   result.attributes = attrs;
672   return mlir::success();
673 }
674 
675 void fir::CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
676                         mlir::func::FuncOp callee, mlir::ValueRange operands) {
677   result.addOperands(operands);
678   result.addAttribute(getCalleeAttrNameStr(), mlir::SymbolRefAttr::get(callee));
679   result.addTypes(callee.getFunctionType().getResults());
680 }
681 
682 void fir::CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
683                         mlir::SymbolRefAttr callee,
684                         llvm::ArrayRef<mlir::Type> results,
685                         mlir::ValueRange operands) {
686   result.addOperands(operands);
687   if (callee)
688     result.addAttribute(getCalleeAttrNameStr(), callee);
689   result.addTypes(results);
690 }
691 
692 //===----------------------------------------------------------------------===//
693 // CmpOp
694 //===----------------------------------------------------------------------===//
695 
696 template <typename OPTY>
697 static void printCmpOp(mlir::OpAsmPrinter &p, OPTY op) {
698   p << ' ';
699   auto predSym = mlir::arith::symbolizeCmpFPredicate(
700       op->template getAttrOfType<mlir::IntegerAttr>(
701             OPTY::getPredicateAttrName())
702           .getInt());
703   assert(predSym && "invalid symbol value for predicate");
704   p << '"' << mlir::arith::stringifyCmpFPredicate(*predSym) << '"' << ", ";
705   p.printOperand(op.getLhs());
706   p << ", ";
707   p.printOperand(op.getRhs());
708   p.printOptionalAttrDict(op->getAttrs(),
709                           /*elidedAttrs=*/{OPTY::getPredicateAttrName()});
710   p << " : " << op.getLhs().getType();
711 }
712 
713 template <typename OPTY>
714 static mlir::ParseResult parseCmpOp(mlir::OpAsmParser &parser,
715                                     mlir::OperationState &result) {
716   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> ops;
717   mlir::NamedAttrList attrs;
718   mlir::Attribute predicateNameAttr;
719   mlir::Type type;
720   if (parser.parseAttribute(predicateNameAttr, OPTY::getPredicateAttrName(),
721                             attrs) ||
722       parser.parseComma() || parser.parseOperandList(ops, 2) ||
723       parser.parseOptionalAttrDict(attrs) || parser.parseColonType(type) ||
724       parser.resolveOperands(ops, type, result.operands))
725     return mlir::failure();
726 
727   if (!predicateNameAttr.isa<mlir::StringAttr>())
728     return parser.emitError(parser.getNameLoc(),
729                             "expected string comparison predicate attribute");
730 
731   // Rewrite string attribute to an enum value.
732   llvm::StringRef predicateName =
733       predicateNameAttr.cast<mlir::StringAttr>().getValue();
734   auto predicate = fir::CmpcOp::getPredicateByName(predicateName);
735   auto builder = parser.getBuilder();
736   mlir::Type i1Type = builder.getI1Type();
737   attrs.set(OPTY::getPredicateAttrName(),
738             builder.getI64IntegerAttr(static_cast<std::int64_t>(predicate)));
739   result.attributes = attrs;
740   result.addTypes({i1Type});
741   return mlir::success();
742 }
743 
744 //===----------------------------------------------------------------------===//
745 // CharConvertOp
746 //===----------------------------------------------------------------------===//
747 
748 mlir::LogicalResult fir::CharConvertOp::verify() {
749   auto unwrap = [&](mlir::Type t) {
750     t = fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t));
751     return t.dyn_cast<fir::CharacterType>();
752   };
753   auto inTy = unwrap(getFrom().getType());
754   auto outTy = unwrap(getTo().getType());
755   if (!(inTy && outTy))
756     return emitOpError("not a reference to a character");
757   if (inTy.getFKind() == outTy.getFKind())
758     return emitOpError("buffers must have different KIND values");
759   return mlir::success();
760 }
761 
762 //===----------------------------------------------------------------------===//
763 // CmpcOp
764 //===----------------------------------------------------------------------===//
765 
766 void fir::buildCmpCOp(mlir::OpBuilder &builder, mlir::OperationState &result,
767                       mlir::arith::CmpFPredicate predicate, mlir::Value lhs,
768                       mlir::Value rhs) {
769   result.addOperands({lhs, rhs});
770   result.types.push_back(builder.getI1Type());
771   result.addAttribute(
772       fir::CmpcOp::getPredicateAttrName(),
773       builder.getI64IntegerAttr(static_cast<std::int64_t>(predicate)));
774 }
775 
776 mlir::arith::CmpFPredicate
777 fir::CmpcOp::getPredicateByName(llvm::StringRef name) {
778   auto pred = mlir::arith::symbolizeCmpFPredicate(name);
779   assert(pred && "invalid predicate name");
780   return *pred;
781 }
782 
783 void fir::CmpcOp::print(mlir::OpAsmPrinter &p) { printCmpOp(p, *this); }
784 
785 mlir::ParseResult fir::CmpcOp::parse(mlir::OpAsmParser &parser,
786                                      mlir::OperationState &result) {
787   return parseCmpOp<fir::CmpcOp>(parser, result);
788 }
789 
790 //===----------------------------------------------------------------------===//
791 // ConstcOp
792 //===----------------------------------------------------------------------===//
793 
794 mlir::ParseResult fir::ConstcOp::parse(mlir::OpAsmParser &parser,
795                                        mlir::OperationState &result) {
796   fir::RealAttr realp;
797   fir::RealAttr imagp;
798   mlir::Type type;
799   if (parser.parseLParen() ||
800       parser.parseAttribute(realp, fir::ConstcOp::realAttrName(),
801                             result.attributes) ||
802       parser.parseComma() ||
803       parser.parseAttribute(imagp, fir::ConstcOp::imagAttrName(),
804                             result.attributes) ||
805       parser.parseRParen() || parser.parseColonType(type) ||
806       parser.addTypesToList(type, result.types))
807     return mlir::failure();
808   return mlir::success();
809 }
810 
811 void fir::ConstcOp::print(mlir::OpAsmPrinter &p) {
812   p << '(';
813   p << getOperation()->getAttr(fir::ConstcOp::realAttrName()) << ", ";
814   p << getOperation()->getAttr(fir::ConstcOp::imagAttrName()) << ") : ";
815   p.printType(getType());
816 }
817 
818 mlir::LogicalResult fir::ConstcOp::verify() {
819   if (!getType().isa<fir::ComplexType>())
820     return emitOpError("must be a !fir.complex type");
821   return mlir::success();
822 }
823 
824 //===----------------------------------------------------------------------===//
825 // ConvertOp
826 //===----------------------------------------------------------------------===//
827 
828 void fir::ConvertOp::getCanonicalizationPatterns(
829     mlir::RewritePatternSet &results, mlir::MLIRContext *context) {
830   results.insert<ConvertConvertOptPattern, ConvertAscendingIndexOptPattern,
831                  ConvertDescendingIndexOptPattern, RedundantConvertOptPattern,
832                  CombineConvertOptPattern, CombineConvertTruncOptPattern,
833                  ForwardConstantConvertPattern>(context);
834 }
835 
836 mlir::OpFoldResult fir::ConvertOp::fold(llvm::ArrayRef<mlir::Attribute> opnds) {
837   if (getValue().getType() == getType())
838     return getValue();
839   if (matchPattern(getValue(), mlir::m_Op<fir::ConvertOp>())) {
840     auto inner = mlir::cast<fir::ConvertOp>(getValue().getDefiningOp());
841     // (convert (convert 'a : logical -> i1) : i1 -> logical) ==> forward 'a
842     if (auto toTy = getType().dyn_cast<fir::LogicalType>())
843       if (auto fromTy = inner.getValue().getType().dyn_cast<fir::LogicalType>())
844         if (inner.getType().isa<mlir::IntegerType>() && (toTy == fromTy))
845           return inner.getValue();
846     // (convert (convert 'a : i1 -> logical) : logical -> i1) ==> forward 'a
847     if (auto toTy = getType().dyn_cast<mlir::IntegerType>())
848       if (auto fromTy =
849               inner.getValue().getType().dyn_cast<mlir::IntegerType>())
850         if (inner.getType().isa<fir::LogicalType>() && (toTy == fromTy) &&
851             (fromTy.getWidth() == 1))
852           return inner.getValue();
853   }
854   return {};
855 }
856 
857 bool fir::ConvertOp::isIntegerCompatible(mlir::Type ty) {
858   return ty.isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType,
859                 fir::LogicalType>();
860 }
861 
862 bool fir::ConvertOp::isFloatCompatible(mlir::Type ty) {
863   return ty.isa<mlir::FloatType, fir::RealType>();
864 }
865 
866 bool fir::ConvertOp::isPointerCompatible(mlir::Type ty) {
867   return ty.isa<fir::ReferenceType, fir::PointerType, fir::HeapType,
868                 fir::LLVMPointerType, mlir::MemRefType, mlir::FunctionType,
869                 fir::TypeDescType>();
870 }
871 
872 mlir::LogicalResult fir::ConvertOp::verify() {
873   auto inType = getValue().getType();
874   auto outType = getType();
875   if (inType == outType)
876     return mlir::success();
877   if ((isPointerCompatible(inType) && isPointerCompatible(outType)) ||
878       (isIntegerCompatible(inType) && isIntegerCompatible(outType)) ||
879       (isIntegerCompatible(inType) && isFloatCompatible(outType)) ||
880       (isFloatCompatible(inType) && isIntegerCompatible(outType)) ||
881       (isFloatCompatible(inType) && isFloatCompatible(outType)) ||
882       (isIntegerCompatible(inType) && isPointerCompatible(outType)) ||
883       (isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
884       (inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
885       (inType.isa<fir::BoxProcType>() && outType.isa<fir::BoxProcType>()) ||
886       (fir::isa_complex(inType) && fir::isa_complex(outType)))
887     return mlir::success();
888   return emitOpError("invalid type conversion");
889 }
890 
891 //===----------------------------------------------------------------------===//
892 // CoordinateOp
893 //===----------------------------------------------------------------------===//
894 
895 void fir::CoordinateOp::print(mlir::OpAsmPrinter &p) {
896   p << ' ' << getRef() << ", " << getCoor();
897   p.printOptionalAttrDict((*this)->getAttrs(), /*elideAttrs=*/{"baseType"});
898   p << " : ";
899   p.printFunctionalType(getOperandTypes(), (*this)->getResultTypes());
900 }
901 
902 mlir::ParseResult fir::CoordinateOp::parse(mlir::OpAsmParser &parser,
903                                            mlir::OperationState &result) {
904   mlir::OpAsmParser::UnresolvedOperand memref;
905   if (parser.parseOperand(memref) || parser.parseComma())
906     return mlir::failure();
907   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> coorOperands;
908   if (parser.parseOperandList(coorOperands))
909     return mlir::failure();
910   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> allOperands;
911   allOperands.push_back(memref);
912   allOperands.append(coorOperands.begin(), coorOperands.end());
913   mlir::FunctionType funcTy;
914   auto loc = parser.getCurrentLocation();
915   if (parser.parseOptionalAttrDict(result.attributes) ||
916       parser.parseColonType(funcTy) ||
917       parser.resolveOperands(allOperands, funcTy.getInputs(), loc,
918                              result.operands) ||
919       parser.addTypesToList(funcTy.getResults(), result.types))
920     return mlir::failure();
921   result.addAttribute("baseType", mlir::TypeAttr::get(funcTy.getInput(0)));
922   return mlir::success();
923 }
924 
925 mlir::LogicalResult fir::CoordinateOp::verify() {
926   const mlir::Type refTy = getRef().getType();
927   if (fir::isa_ref_type(refTy)) {
928     auto eleTy = fir::dyn_cast_ptrEleTy(refTy);
929     if (auto arrTy = eleTy.dyn_cast<fir::SequenceType>()) {
930       if (arrTy.hasUnknownShape())
931         return emitOpError("cannot find coordinate in unknown shape");
932       if (arrTy.getConstantRows() < arrTy.getDimension() - 1)
933         return emitOpError("cannot find coordinate with unknown extents");
934     }
935     if (!(fir::isa_aggregate(eleTy) || fir::isa_complex(eleTy) ||
936           fir::isa_char_string(eleTy)))
937       return emitOpError("cannot apply to this element type");
938   }
939   auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(refTy);
940   unsigned dimension = 0;
941   const unsigned numCoors = getCoor().size();
942   for (auto coorOperand : llvm::enumerate(getCoor())) {
943     auto co = coorOperand.value();
944     if (dimension == 0 && eleTy.isa<fir::SequenceType>()) {
945       dimension = eleTy.cast<fir::SequenceType>().getDimension();
946       if (dimension == 0)
947         return emitOpError("cannot apply to array of unknown rank");
948     }
949     if (auto *defOp = co.getDefiningOp()) {
950       if (auto index = mlir::dyn_cast<fir::LenParamIndexOp>(defOp)) {
951         // Recovering a LEN type parameter only makes sense from a boxed
952         // value. For a bare reference, the LEN type parameters must be
953         // passed as additional arguments to `index`.
954         if (refTy.isa<fir::BoxType>()) {
955           if (coorOperand.index() != numCoors - 1)
956             return emitOpError("len_param_index must be last argument");
957           if (getNumOperands() != 2)
958             return emitOpError("too many operands for len_param_index case");
959         }
960         if (eleTy != index.getOnType())
961           emitOpError(
962               "len_param_index type not compatible with reference type");
963         return mlir::success();
964       } else if (auto index = mlir::dyn_cast<fir::FieldIndexOp>(defOp)) {
965         if (eleTy != index.getOnType())
966           emitOpError("field_index type not compatible with reference type");
967         if (auto recTy = eleTy.dyn_cast<fir::RecordType>()) {
968           eleTy = recTy.getType(index.getFieldName());
969           continue;
970         }
971         return emitOpError("field_index not applied to !fir.type");
972       }
973     }
974     if (dimension) {
975       if (--dimension == 0)
976         eleTy = eleTy.cast<fir::SequenceType>().getEleTy();
977     } else {
978       if (auto t = eleTy.dyn_cast<mlir::TupleType>()) {
979         // FIXME: Generally, we don't know which field of the tuple is being
980         // referred to unless the operand is a constant. Just assume everything
981         // is good in the tuple case for now.
982         return mlir::success();
983       } else if (auto t = eleTy.dyn_cast<fir::RecordType>()) {
984         // FIXME: This is the same as the tuple case.
985         return mlir::success();
986       } else if (auto t = eleTy.dyn_cast<fir::ComplexType>()) {
987         eleTy = t.getElementType();
988       } else if (auto t = eleTy.dyn_cast<mlir::ComplexType>()) {
989         eleTy = t.getElementType();
990       } else if (auto t = eleTy.dyn_cast<fir::CharacterType>()) {
991         if (t.getLen() == fir::CharacterType::singleton())
992           return emitOpError("cannot apply to character singleton");
993         eleTy = fir::CharacterType::getSingleton(t.getContext(), t.getFKind());
994         if (fir::unwrapRefType(getType()) != eleTy)
995           return emitOpError("character type mismatch");
996       } else {
997         return emitOpError("invalid parameters (too many)");
998       }
999     }
1000   }
1001   return mlir::success();
1002 }
1003 
1004 //===----------------------------------------------------------------------===//
1005 // DispatchOp
1006 //===----------------------------------------------------------------------===//
1007 
1008 mlir::FunctionType fir::DispatchOp::getFunctionType() {
1009   return mlir::FunctionType::get(getContext(), getOperandTypes(),
1010                                  getResultTypes());
1011 }
1012 
1013 mlir::ParseResult fir::DispatchOp::parse(mlir::OpAsmParser &parser,
1014                                          mlir::OperationState &result) {
1015   mlir::FunctionType calleeType;
1016   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
1017   auto calleeLoc = parser.getNameLoc();
1018   llvm::StringRef calleeName;
1019   if (failed(parser.parseOptionalKeyword(&calleeName))) {
1020     mlir::StringAttr calleeAttr;
1021     if (parser.parseAttribute(calleeAttr,
1022                               fir::DispatchOp::getMethodAttrNameStr(),
1023                               result.attributes))
1024       return mlir::failure();
1025   } else {
1026     result.addAttribute(fir::DispatchOp::getMethodAttrNameStr(),
1027                         parser.getBuilder().getStringAttr(calleeName));
1028   }
1029   if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::Paren) ||
1030       parser.parseOptionalAttrDict(result.attributes) ||
1031       parser.parseColonType(calleeType) ||
1032       parser.addTypesToList(calleeType.getResults(), result.types) ||
1033       parser.resolveOperands(operands, calleeType.getInputs(), calleeLoc,
1034                              result.operands))
1035     return mlir::failure();
1036   return mlir::success();
1037 }
1038 
1039 void fir::DispatchOp::print(mlir::OpAsmPrinter &p) {
1040   p << ' ' << getMethodAttr() << '(';
1041   p.printOperand(getObject());
1042   if (!getArgs().empty()) {
1043     p << ", ";
1044     p.printOperands(getArgs());
1045   }
1046   p << ") : ";
1047   p.printFunctionalType(getOperation()->getOperandTypes(),
1048                         getOperation()->getResultTypes());
1049 }
1050 
1051 //===----------------------------------------------------------------------===//
1052 // DispatchTableOp
1053 //===----------------------------------------------------------------------===//
1054 
1055 void fir::DispatchTableOp::appendTableEntry(mlir::Operation *op) {
1056   assert(mlir::isa<fir::DTEntryOp>(*op) && "operation must be a DTEntryOp");
1057   auto &block = getBlock();
1058   block.getOperations().insert(block.end(), op);
1059 }
1060 
1061 mlir::ParseResult fir::DispatchTableOp::parse(mlir::OpAsmParser &parser,
1062                                               mlir::OperationState &result) {
1063   // Parse the name as a symbol reference attribute.
1064   mlir::SymbolRefAttr nameAttr;
1065   if (parser.parseAttribute(nameAttr, mlir::SymbolTable::getSymbolAttrName(),
1066                             result.attributes))
1067     return mlir::failure();
1068 
1069   // Convert the parsed name attr into a string attr.
1070   result.attributes.set(mlir::SymbolTable::getSymbolAttrName(),
1071                         nameAttr.getRootReference());
1072 
1073   // Parse the optional table body.
1074   mlir::Region *body = result.addRegion();
1075   mlir::OptionalParseResult parseResult = parser.parseOptionalRegion(*body);
1076   if (parseResult.has_value() && failed(*parseResult))
1077     return mlir::failure();
1078 
1079   fir::DispatchTableOp::ensureTerminator(*body, parser.getBuilder(),
1080                                          result.location);
1081   return mlir::success();
1082 }
1083 
1084 void fir::DispatchTableOp::print(mlir::OpAsmPrinter &p) {
1085   auto tableName = getOperation()
1086                        ->getAttrOfType<mlir::StringAttr>(
1087                            mlir::SymbolTable::getSymbolAttrName())
1088                        .getValue();
1089   p << " @" << tableName;
1090 
1091   mlir::Region &body = getOperation()->getRegion(0);
1092   if (!body.empty()) {
1093     p << ' ';
1094     p.printRegion(body, /*printEntryBlockArgs=*/false,
1095                   /*printBlockTerminators=*/false);
1096   }
1097 }
1098 
1099 mlir::LogicalResult fir::DispatchTableOp::verify() {
1100   for (auto &op : getBlock())
1101     if (!mlir::isa<fir::DTEntryOp, fir::FirEndOp>(op))
1102       return op.emitOpError("dispatch table must contain dt_entry");
1103   return mlir::success();
1104 }
1105 
1106 //===----------------------------------------------------------------------===//
1107 // EmboxOp
1108 //===----------------------------------------------------------------------===//
1109 
1110 mlir::LogicalResult fir::EmboxOp::verify() {
1111   auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());
1112   bool isArray = false;
1113   if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>()) {
1114     eleTy = seqTy.getEleTy();
1115     isArray = true;
1116   }
1117   if (hasLenParams()) {
1118     auto lenPs = numLenParams();
1119     if (auto rt = eleTy.dyn_cast<fir::RecordType>()) {
1120       if (lenPs != rt.getNumLenParams())
1121         return emitOpError("number of LEN params does not correspond"
1122                            " to the !fir.type type");
1123     } else if (auto strTy = eleTy.dyn_cast<fir::CharacterType>()) {
1124       if (strTy.getLen() != fir::CharacterType::unknownLen())
1125         return emitOpError("CHARACTER already has static LEN");
1126     } else {
1127       return emitOpError("LEN parameters require CHARACTER or derived type");
1128     }
1129     for (auto lp : getTypeparams())
1130       if (!fir::isa_integer(lp.getType()))
1131         return emitOpError("LEN parameters must be integral type");
1132   }
1133   if (getShape() && !isArray)
1134     return emitOpError("shape must not be provided for a scalar");
1135   if (getSlice() && !isArray)
1136     return emitOpError("slice must not be provided for a scalar");
1137   return mlir::success();
1138 }
1139 
1140 //===----------------------------------------------------------------------===//
1141 // EmboxCharOp
1142 //===----------------------------------------------------------------------===//
1143 
1144 mlir::LogicalResult fir::EmboxCharOp::verify() {
1145   auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());
1146   if (!eleTy.dyn_cast_or_null<fir::CharacterType>())
1147     return mlir::failure();
1148   return mlir::success();
1149 }
1150 
1151 //===----------------------------------------------------------------------===//
1152 // EmboxProcOp
1153 //===----------------------------------------------------------------------===//
1154 
1155 mlir::LogicalResult fir::EmboxProcOp::verify() {
1156   // host bindings (optional) must be a reference to a tuple
1157   if (auto h = getHost()) {
1158     if (auto r = h.getType().dyn_cast<fir::ReferenceType>())
1159       if (r.getEleTy().isa<mlir::TupleType>())
1160         return mlir::success();
1161     return mlir::failure();
1162   }
1163   return mlir::success();
1164 }
1165 
1166 //===----------------------------------------------------------------------===//
1167 // GenTypeDescOp
1168 //===----------------------------------------------------------------------===//
1169 
1170 void fir::GenTypeDescOp::build(mlir::OpBuilder &, mlir::OperationState &result,
1171                                mlir::TypeAttr inty) {
1172   result.addAttribute("in_type", inty);
1173   result.addTypes(TypeDescType::get(inty.getValue()));
1174 }
1175 
1176 mlir::ParseResult fir::GenTypeDescOp::parse(mlir::OpAsmParser &parser,
1177                                             mlir::OperationState &result) {
1178   mlir::Type intype;
1179   if (parser.parseType(intype))
1180     return mlir::failure();
1181   result.addAttribute("in_type", mlir::TypeAttr::get(intype));
1182   mlir::Type restype = fir::TypeDescType::get(intype);
1183   if (parser.addTypeToList(restype, result.types))
1184     return mlir::failure();
1185   return mlir::success();
1186 }
1187 
1188 void fir::GenTypeDescOp::print(mlir::OpAsmPrinter &p) {
1189   p << ' ' << getOperation()->getAttr("in_type");
1190   p.printOptionalAttrDict(getOperation()->getAttrs(), {"in_type"});
1191 }
1192 
1193 mlir::LogicalResult fir::GenTypeDescOp::verify() {
1194   mlir::Type resultTy = getType();
1195   if (auto tdesc = resultTy.dyn_cast<fir::TypeDescType>()) {
1196     if (tdesc.getOfTy() != getInType())
1197       return emitOpError("wrapped type mismatched");
1198     return mlir::success();
1199   }
1200   return emitOpError("must be !fir.tdesc type");
1201 }
1202 
1203 //===----------------------------------------------------------------------===//
1204 // GlobalOp
1205 //===----------------------------------------------------------------------===//
1206 
1207 mlir::Type fir::GlobalOp::resultType() {
1208   return wrapAllocaResultType(getType());
1209 }
1210 
1211 mlir::ParseResult fir::GlobalOp::parse(mlir::OpAsmParser &parser,
1212                                        mlir::OperationState &result) {
1213   // Parse the optional linkage
1214   llvm::StringRef linkage;
1215   auto &builder = parser.getBuilder();
1216   if (mlir::succeeded(parser.parseOptionalKeyword(&linkage))) {
1217     if (fir::GlobalOp::verifyValidLinkage(linkage))
1218       return mlir::failure();
1219     mlir::StringAttr linkAttr = builder.getStringAttr(linkage);
1220     result.addAttribute(fir::GlobalOp::linkageAttrName(), linkAttr);
1221   }
1222 
1223   // Parse the name as a symbol reference attribute.
1224   mlir::SymbolRefAttr nameAttr;
1225   if (parser.parseAttribute(nameAttr, fir::GlobalOp::symbolAttrNameStr(),
1226                             result.attributes))
1227     return mlir::failure();
1228   result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
1229                       nameAttr.getRootReference());
1230 
1231   bool simpleInitializer = false;
1232   if (mlir::succeeded(parser.parseOptionalLParen())) {
1233     mlir::Attribute attr;
1234     if (parser.parseAttribute(attr, "initVal", result.attributes) ||
1235         parser.parseRParen())
1236       return mlir::failure();
1237     simpleInitializer = true;
1238   }
1239 
1240   if (succeeded(parser.parseOptionalKeyword("constant"))) {
1241     // if "constant" keyword then mark this as a constant, not a variable
1242     result.addAttribute("constant", builder.getUnitAttr());
1243   }
1244 
1245   mlir::Type globalType;
1246   if (parser.parseColonType(globalType))
1247     return mlir::failure();
1248 
1249   result.addAttribute(fir::GlobalOp::getTypeAttrName(result.name),
1250                       mlir::TypeAttr::get(globalType));
1251 
1252   if (simpleInitializer) {
1253     result.addRegion();
1254   } else {
1255     // Parse the optional initializer body.
1256     auto parseResult =
1257         parser.parseOptionalRegion(*result.addRegion(), /*arguments=*/{});
1258     if (parseResult.has_value() && mlir::failed(*parseResult))
1259       return mlir::failure();
1260   }
1261   return mlir::success();
1262 }
1263 
1264 void fir::GlobalOp::print(mlir::OpAsmPrinter &p) {
1265   if (getLinkName())
1266     p << ' ' << *getLinkName();
1267   p << ' ';
1268   p.printAttributeWithoutType(getSymrefAttr());
1269   if (auto val = getValueOrNull())
1270     p << '(' << val << ')';
1271   if (getOperation()->getAttr(fir::GlobalOp::getConstantAttrNameStr()))
1272     p << " constant";
1273   p << " : ";
1274   p.printType(getType());
1275   if (hasInitializationBody()) {
1276     p << ' ';
1277     p.printRegion(getOperation()->getRegion(0),
1278                   /*printEntryBlockArgs=*/false,
1279                   /*printBlockTerminators=*/true);
1280   }
1281 }
1282 
1283 void fir::GlobalOp::appendInitialValue(mlir::Operation *op) {
1284   getBlock().getOperations().push_back(op);
1285 }
1286 
1287 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1288                           mlir::OperationState &result, llvm::StringRef name,
1289                           bool isConstant, mlir::Type type,
1290                           mlir::Attribute initialVal, mlir::StringAttr linkage,
1291                           llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1292   result.addRegion();
1293   result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type));
1294   result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
1295                       builder.getStringAttr(name));
1296   result.addAttribute(symbolAttrNameStr(),
1297                       mlir::SymbolRefAttr::get(builder.getContext(), name));
1298   if (isConstant)
1299     result.addAttribute(getConstantAttrName(result.name),
1300                         builder.getUnitAttr());
1301   if (initialVal)
1302     result.addAttribute(getInitValAttrName(result.name), initialVal);
1303   if (linkage)
1304     result.addAttribute(linkageAttrName(), linkage);
1305   result.attributes.append(attrs.begin(), attrs.end());
1306 }
1307 
1308 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1309                           mlir::OperationState &result, llvm::StringRef name,
1310                           mlir::Type type, mlir::Attribute initialVal,
1311                           mlir::StringAttr linkage,
1312                           llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1313   build(builder, result, name, /*isConstant=*/false, type, {}, linkage, attrs);
1314 }
1315 
1316 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1317                           mlir::OperationState &result, llvm::StringRef name,
1318                           bool isConstant, mlir::Type type,
1319                           mlir::StringAttr linkage,
1320                           llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1321   build(builder, result, name, isConstant, type, {}, linkage, attrs);
1322 }
1323 
1324 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1325                           mlir::OperationState &result, llvm::StringRef name,
1326                           mlir::Type type, mlir::StringAttr linkage,
1327                           llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1328   build(builder, result, name, /*isConstant=*/false, type, {}, linkage, attrs);
1329 }
1330 
1331 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1332                           mlir::OperationState &result, llvm::StringRef name,
1333                           bool isConstant, mlir::Type type,
1334                           llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1335   build(builder, result, name, isConstant, type, mlir::StringAttr{}, attrs);
1336 }
1337 
1338 void fir::GlobalOp::build(mlir::OpBuilder &builder,
1339                           mlir::OperationState &result, llvm::StringRef name,
1340                           mlir::Type type,
1341                           llvm::ArrayRef<mlir::NamedAttribute> attrs) {
1342   build(builder, result, name, /*isConstant=*/false, type, attrs);
1343 }
1344 
1345 mlir::ParseResult fir::GlobalOp::verifyValidLinkage(llvm::StringRef linkage) {
1346   // Supporting only a subset of the LLVM linkage types for now
1347   static const char *validNames[] = {"common", "internal", "linkonce",
1348                                      "linkonce_odr", "weak"};
1349   return mlir::success(llvm::is_contained(validNames, linkage));
1350 }
1351 
1352 //===----------------------------------------------------------------------===//
1353 // GlobalLenOp
1354 //===----------------------------------------------------------------------===//
1355 
1356 mlir::ParseResult fir::GlobalLenOp::parse(mlir::OpAsmParser &parser,
1357                                           mlir::OperationState &result) {
1358   llvm::StringRef fieldName;
1359   if (failed(parser.parseOptionalKeyword(&fieldName))) {
1360     mlir::StringAttr fieldAttr;
1361     if (parser.parseAttribute(fieldAttr, fir::GlobalLenOp::lenParamAttrName(),
1362                               result.attributes))
1363       return mlir::failure();
1364   } else {
1365     result.addAttribute(fir::GlobalLenOp::lenParamAttrName(),
1366                         parser.getBuilder().getStringAttr(fieldName));
1367   }
1368   mlir::IntegerAttr constant;
1369   if (parser.parseComma() ||
1370       parser.parseAttribute(constant, fir::GlobalLenOp::intAttrName(),
1371                             result.attributes))
1372     return mlir::failure();
1373   return mlir::success();
1374 }
1375 
1376 void fir::GlobalLenOp::print(mlir::OpAsmPrinter &p) {
1377   p << ' ' << getOperation()->getAttr(fir::GlobalLenOp::lenParamAttrName())
1378     << ", " << getOperation()->getAttr(fir::GlobalLenOp::intAttrName());
1379 }
1380 
1381 //===----------------------------------------------------------------------===//
1382 // FieldIndexOp
1383 //===----------------------------------------------------------------------===//
1384 
1385 template <typename TY>
1386 mlir::ParseResult parseFieldLikeOp(mlir::OpAsmParser &parser,
1387                                    mlir::OperationState &result) {
1388   llvm::StringRef fieldName;
1389   auto &builder = parser.getBuilder();
1390   mlir::Type recty;
1391   if (parser.parseOptionalKeyword(&fieldName) || parser.parseComma() ||
1392       parser.parseType(recty))
1393     return mlir::failure();
1394   result.addAttribute(fir::FieldIndexOp::getFieldAttrName(),
1395                       builder.getStringAttr(fieldName));
1396   if (!recty.dyn_cast<fir::RecordType>())
1397     return mlir::failure();
1398   result.addAttribute(fir::FieldIndexOp::getTypeAttrName(),
1399                       mlir::TypeAttr::get(recty));
1400   if (!parser.parseOptionalLParen()) {
1401     llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
1402     llvm::SmallVector<mlir::Type> types;
1403     auto loc = parser.getNameLoc();
1404     if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None) ||
1405         parser.parseColonTypeList(types) || parser.parseRParen() ||
1406         parser.resolveOperands(operands, types, loc, result.operands))
1407       return mlir::failure();
1408   }
1409   mlir::Type fieldType = TY::get(builder.getContext());
1410   if (parser.addTypeToList(fieldType, result.types))
1411     return mlir::failure();
1412   return mlir::success();
1413 }
1414 
1415 mlir::ParseResult fir::FieldIndexOp::parse(mlir::OpAsmParser &parser,
1416                                            mlir::OperationState &result) {
1417   return parseFieldLikeOp<fir::FieldType>(parser, result);
1418 }
1419 
1420 template <typename OP>
1421 void printFieldLikeOp(mlir::OpAsmPrinter &p, OP &op) {
1422   p << ' '
1423     << op.getOperation()
1424            ->template getAttrOfType<mlir::StringAttr>(
1425                fir::FieldIndexOp::getFieldAttrName())
1426            .getValue()
1427     << ", " << op.getOperation()->getAttr(fir::FieldIndexOp::getTypeAttrName());
1428   if (op.getNumOperands()) {
1429     p << '(';
1430     p.printOperands(op.getTypeparams());
1431     auto sep = ") : ";
1432     for (auto op : op.getTypeparams()) {
1433       p << sep;
1434       if (op)
1435         p.printType(op.getType());
1436       else
1437         p << "()";
1438       sep = ", ";
1439     }
1440   }
1441 }
1442 
1443 void fir::FieldIndexOp::print(mlir::OpAsmPrinter &p) {
1444   printFieldLikeOp(p, *this);
1445 }
1446 
1447 void fir::FieldIndexOp::build(mlir::OpBuilder &builder,
1448                               mlir::OperationState &result,
1449                               llvm::StringRef fieldName, mlir::Type recTy,
1450                               mlir::ValueRange operands) {
1451   result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));
1452   result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));
1453   result.addOperands(operands);
1454 }
1455 
1456 llvm::SmallVector<mlir::Attribute> fir::FieldIndexOp::getAttributes() {
1457   llvm::SmallVector<mlir::Attribute> attrs;
1458   attrs.push_back(getFieldIdAttr());
1459   attrs.push_back(getOnTypeAttr());
1460   return attrs;
1461 }
1462 
1463 //===----------------------------------------------------------------------===//
1464 // InsertOnRangeOp
1465 //===----------------------------------------------------------------------===//
1466 
1467 static mlir::ParseResult
1468 parseCustomRangeSubscript(mlir::OpAsmParser &parser,
1469                           mlir::DenseIntElementsAttr &coord) {
1470   llvm::SmallVector<std::int64_t> lbounds;
1471   llvm::SmallVector<std::int64_t> ubounds;
1472   if (parser.parseKeyword("from") ||
1473       parser.parseCommaSeparatedList(
1474           mlir::AsmParser::Delimiter::Paren,
1475           [&] { return parser.parseInteger(lbounds.emplace_back(0)); }) ||
1476       parser.parseKeyword("to") ||
1477       parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::Paren, [&] {
1478         return parser.parseInteger(ubounds.emplace_back(0));
1479       }))
1480     return mlir::failure();
1481   llvm::SmallVector<std::int64_t> zippedBounds;
1482   for (auto zip : llvm::zip(lbounds, ubounds)) {
1483     zippedBounds.push_back(std::get<0>(zip));
1484     zippedBounds.push_back(std::get<1>(zip));
1485   }
1486   coord = mlir::Builder(parser.getContext()).getIndexTensorAttr(zippedBounds);
1487   return mlir::success();
1488 }
1489 
1490 static void printCustomRangeSubscript(mlir::OpAsmPrinter &printer,
1491                                       fir::InsertOnRangeOp op,
1492                                       mlir::DenseIntElementsAttr coord) {
1493   printer << "from (";
1494   auto enumerate = llvm::enumerate(coord.getValues<std::int64_t>());
1495   // Even entries are the lower bounds.
1496   llvm::interleaveComma(
1497       make_filter_range(
1498           enumerate,
1499           [](auto indexed_value) { return indexed_value.index() % 2 == 0; }),
1500       printer, [&](auto indexed_value) { printer << indexed_value.value(); });
1501   printer << ") to (";
1502   // Odd entries are the upper bounds.
1503   llvm::interleaveComma(
1504       make_filter_range(
1505           enumerate,
1506           [](auto indexed_value) { return indexed_value.index() % 2 != 0; }),
1507       printer, [&](auto indexed_value) { printer << indexed_value.value(); });
1508   printer << ")";
1509 }
1510 
1511 /// Range bounds must be nonnegative, and the range must not be empty.
1512 mlir::LogicalResult fir::InsertOnRangeOp::verify() {
1513   if (fir::hasDynamicSize(getSeq().getType()))
1514     return emitOpError("must have constant shape and size");
1515   mlir::DenseIntElementsAttr coorAttr = getCoor();
1516   if (coorAttr.size() < 2 || coorAttr.size() % 2 != 0)
1517     return emitOpError("has uneven number of values in ranges");
1518   bool rangeIsKnownToBeNonempty = false;
1519   for (auto i = coorAttr.getValues<std::int64_t>().end(),
1520             b = coorAttr.getValues<std::int64_t>().begin();
1521        i != b;) {
1522     int64_t ub = (*--i);
1523     int64_t lb = (*--i);
1524     if (lb < 0 || ub < 0)
1525       return emitOpError("negative range bound");
1526     if (rangeIsKnownToBeNonempty)
1527       continue;
1528     if (lb > ub)
1529       return emitOpError("empty range");
1530     rangeIsKnownToBeNonempty = lb < ub;
1531   }
1532   return mlir::success();
1533 }
1534 
1535 //===----------------------------------------------------------------------===//
1536 // InsertValueOp
1537 //===----------------------------------------------------------------------===//
1538 
1539 static bool checkIsIntegerConstant(mlir::Attribute attr, std::int64_t conVal) {
1540   if (auto iattr = attr.dyn_cast<mlir::IntegerAttr>())
1541     return iattr.getInt() == conVal;
1542   return false;
1543 }
1544 
1545 static bool isZero(mlir::Attribute a) { return checkIsIntegerConstant(a, 0); }
1546 static bool isOne(mlir::Attribute a) { return checkIsIntegerConstant(a, 1); }
1547 
1548 // Undo some complex patterns created in the front-end and turn them back into
1549 // complex ops.
1550 template <typename FltOp, typename CpxOp>
1551 struct UndoComplexPattern : public mlir::RewritePattern {
1552   UndoComplexPattern(mlir::MLIRContext *ctx)
1553       : mlir::RewritePattern("fir.insert_value", 2, ctx) {}
1554 
1555   mlir::LogicalResult
1556   matchAndRewrite(mlir::Operation *op,
1557                   mlir::PatternRewriter &rewriter) const override {
1558     auto insval = mlir::dyn_cast_or_null<fir::InsertValueOp>(op);
1559     if (!insval || !insval.getType().isa<fir::ComplexType>())
1560       return mlir::failure();
1561     auto insval2 = mlir::dyn_cast_or_null<fir::InsertValueOp>(
1562         insval.getAdt().getDefiningOp());
1563     if (!insval2)
1564       return mlir::failure();
1565     auto binf = mlir::dyn_cast_or_null<FltOp>(insval.getVal().getDefiningOp());
1566     auto binf2 =
1567         mlir::dyn_cast_or_null<FltOp>(insval2.getVal().getDefiningOp());
1568     if (!binf || !binf2 || insval.getCoor().size() != 1 ||
1569         !isOne(insval.getCoor()[0]) || insval2.getCoor().size() != 1 ||
1570         !isZero(insval2.getCoor()[0]))
1571       return mlir::failure();
1572     auto eai = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
1573         binf.getLhs().getDefiningOp());
1574     auto ebi = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
1575         binf.getRhs().getDefiningOp());
1576     auto ear = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
1577         binf2.getLhs().getDefiningOp());
1578     auto ebr = mlir::dyn_cast_or_null<fir::ExtractValueOp>(
1579         binf2.getRhs().getDefiningOp());
1580     if (!eai || !ebi || !ear || !ebr || ear.getAdt() != eai.getAdt() ||
1581         ebr.getAdt() != ebi.getAdt() || eai.getCoor().size() != 1 ||
1582         !isOne(eai.getCoor()[0]) || ebi.getCoor().size() != 1 ||
1583         !isOne(ebi.getCoor()[0]) || ear.getCoor().size() != 1 ||
1584         !isZero(ear.getCoor()[0]) || ebr.getCoor().size() != 1 ||
1585         !isZero(ebr.getCoor()[0]))
1586       return mlir::failure();
1587     rewriter.replaceOpWithNewOp<CpxOp>(op, ear.getAdt(), ebr.getAdt());
1588     return mlir::success();
1589   }
1590 };
1591 
1592 void fir::InsertValueOp::getCanonicalizationPatterns(
1593     mlir::RewritePatternSet &results, mlir::MLIRContext *context) {
1594   results.insert<UndoComplexPattern<mlir::arith::AddFOp, fir::AddcOp>,
1595                  UndoComplexPattern<mlir::arith::SubFOp, fir::SubcOp>>(context);
1596 }
1597 
1598 //===----------------------------------------------------------------------===//
1599 // IterWhileOp
1600 //===----------------------------------------------------------------------===//
1601 
1602 void fir::IterWhileOp::build(mlir::OpBuilder &builder,
1603                              mlir::OperationState &result, mlir::Value lb,
1604                              mlir::Value ub, mlir::Value step,
1605                              mlir::Value iterate, bool finalCountValue,
1606                              mlir::ValueRange iterArgs,
1607                              llvm::ArrayRef<mlir::NamedAttribute> attributes) {
1608   result.addOperands({lb, ub, step, iterate});
1609   if (finalCountValue) {
1610     result.addTypes(builder.getIndexType());
1611     result.addAttribute(getFinalValueAttrNameStr(), builder.getUnitAttr());
1612   }
1613   result.addTypes(iterate.getType());
1614   result.addOperands(iterArgs);
1615   for (auto v : iterArgs)
1616     result.addTypes(v.getType());
1617   mlir::Region *bodyRegion = result.addRegion();
1618   bodyRegion->push_back(new mlir::Block{});
1619   bodyRegion->front().addArgument(builder.getIndexType(), result.location);
1620   bodyRegion->front().addArgument(iterate.getType(), result.location);
1621   bodyRegion->front().addArguments(
1622       iterArgs.getTypes(),
1623       llvm::SmallVector<mlir::Location>(iterArgs.size(), result.location));
1624   result.addAttributes(attributes);
1625 }
1626 
1627 mlir::ParseResult fir::IterWhileOp::parse(mlir::OpAsmParser &parser,
1628                                           mlir::OperationState &result) {
1629   auto &builder = parser.getBuilder();
1630   mlir::OpAsmParser::Argument inductionVariable, iterateVar;
1631   mlir::OpAsmParser::UnresolvedOperand lb, ub, step, iterateInput;
1632   if (parser.parseLParen() || parser.parseArgument(inductionVariable) ||
1633       parser.parseEqual())
1634     return mlir::failure();
1635 
1636   // Parse loop bounds.
1637   auto indexType = builder.getIndexType();
1638   auto i1Type = builder.getIntegerType(1);
1639   if (parser.parseOperand(lb) ||
1640       parser.resolveOperand(lb, indexType, result.operands) ||
1641       parser.parseKeyword("to") || parser.parseOperand(ub) ||
1642       parser.resolveOperand(ub, indexType, result.operands) ||
1643       parser.parseKeyword("step") || parser.parseOperand(step) ||
1644       parser.parseRParen() ||
1645       parser.resolveOperand(step, indexType, result.operands) ||
1646       parser.parseKeyword("and") || parser.parseLParen() ||
1647       parser.parseArgument(iterateVar) || parser.parseEqual() ||
1648       parser.parseOperand(iterateInput) || parser.parseRParen() ||
1649       parser.resolveOperand(iterateInput, i1Type, result.operands))
1650     return mlir::failure();
1651 
1652   // Parse the initial iteration arguments.
1653   auto prependCount = false;
1654 
1655   // Induction variable.
1656   llvm::SmallVector<mlir::OpAsmParser::Argument> regionArgs;
1657   regionArgs.push_back(inductionVariable);
1658   regionArgs.push_back(iterateVar);
1659 
1660   if (succeeded(parser.parseOptionalKeyword("iter_args"))) {
1661     llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
1662     llvm::SmallVector<mlir::Type> regionTypes;
1663     // Parse assignment list and results type list.
1664     if (parser.parseAssignmentList(regionArgs, operands) ||
1665         parser.parseArrowTypeList(regionTypes))
1666       return mlir::failure();
1667     if (regionTypes.size() == operands.size() + 2)
1668       prependCount = true;
1669     llvm::ArrayRef<mlir::Type> resTypes = regionTypes;
1670     resTypes = prependCount ? resTypes.drop_front(2) : resTypes;
1671     // Resolve input operands.
1672     for (auto operandType : llvm::zip(operands, resTypes))
1673       if (parser.resolveOperand(std::get<0>(operandType),
1674                                 std::get<1>(operandType), result.operands))
1675         return mlir::failure();
1676     if (prependCount) {
1677       result.addTypes(regionTypes);
1678     } else {
1679       result.addTypes(i1Type);
1680       result.addTypes(resTypes);
1681     }
1682   } else if (succeeded(parser.parseOptionalArrow())) {
1683     llvm::SmallVector<mlir::Type> typeList;
1684     if (parser.parseLParen() || parser.parseTypeList(typeList) ||
1685         parser.parseRParen())
1686       return mlir::failure();
1687     // Type list must be "(index, i1)".
1688     if (typeList.size() != 2 || !typeList[0].isa<mlir::IndexType>() ||
1689         !typeList[1].isSignlessInteger(1))
1690       return mlir::failure();
1691     result.addTypes(typeList);
1692     prependCount = true;
1693   } else {
1694     result.addTypes(i1Type);
1695   }
1696 
1697   if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1698     return mlir::failure();
1699 
1700   llvm::SmallVector<mlir::Type> argTypes;
1701   // Induction variable (hidden)
1702   if (prependCount)
1703     result.addAttribute(IterWhileOp::getFinalValueAttrNameStr(),
1704                         builder.getUnitAttr());
1705   else
1706     argTypes.push_back(indexType);
1707   // Loop carried variables (including iterate)
1708   argTypes.append(result.types.begin(), result.types.end());
1709   // Parse the body region.
1710   auto *body = result.addRegion();
1711   if (regionArgs.size() != argTypes.size())
1712     return parser.emitError(
1713         parser.getNameLoc(),
1714         "mismatch in number of loop-carried values and defined values");
1715 
1716   for (size_t i = 0, e = regionArgs.size(); i != e; ++i)
1717     regionArgs[i].type = argTypes[i];
1718 
1719   if (parser.parseRegion(*body, regionArgs))
1720     return mlir::failure();
1721 
1722   fir::IterWhileOp::ensureTerminator(*body, builder, result.location);
1723   return mlir::success();
1724 }
1725 
1726 mlir::LogicalResult fir::IterWhileOp::verify() {
1727   // Check that the body defines as single block argument for the induction
1728   // variable.
1729   auto *body = getBody();
1730   if (!body->getArgument(1).getType().isInteger(1))
1731     return emitOpError(
1732         "expected body second argument to be an index argument for "
1733         "the induction variable");
1734   if (!body->getArgument(0).getType().isIndex())
1735     return emitOpError(
1736         "expected body first argument to be an index argument for "
1737         "the induction variable");
1738 
1739   auto opNumResults = getNumResults();
1740   if (getFinalValue()) {
1741     // Result type must be "(index, i1, ...)".
1742     if (!getResult(0).getType().isa<mlir::IndexType>())
1743       return emitOpError("result #0 expected to be index");
1744     if (!getResult(1).getType().isSignlessInteger(1))
1745       return emitOpError("result #1 expected to be i1");
1746     opNumResults--;
1747   } else {
1748     // iterate_while always returns the early exit induction value.
1749     // Result type must be "(i1, ...)"
1750     if (!getResult(0).getType().isSignlessInteger(1))
1751       return emitOpError("result #0 expected to be i1");
1752   }
1753   if (opNumResults == 0)
1754     return mlir::failure();
1755   if (getNumIterOperands() != opNumResults)
1756     return emitOpError(
1757         "mismatch in number of loop-carried values and defined values");
1758   if (getNumRegionIterArgs() != opNumResults)
1759     return emitOpError(
1760         "mismatch in number of basic block args and defined values");
1761   auto iterOperands = getIterOperands();
1762   auto iterArgs = getRegionIterArgs();
1763   auto opResults = getFinalValue() ? getResults().drop_front() : getResults();
1764   unsigned i = 0u;
1765   for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {
1766     if (std::get<0>(e).getType() != std::get<2>(e).getType())
1767       return emitOpError() << "types mismatch between " << i
1768                            << "th iter operand and defined value";
1769     if (std::get<1>(e).getType() != std::get<2>(e).getType())
1770       return emitOpError() << "types mismatch between " << i
1771                            << "th iter region arg and defined value";
1772 
1773     i++;
1774   }
1775   return mlir::success();
1776 }
1777 
1778 void fir::IterWhileOp::print(mlir::OpAsmPrinter &p) {
1779   p << " (" << getInductionVar() << " = " << getLowerBound() << " to "
1780     << getUpperBound() << " step " << getStep() << ") and (";
1781   assert(hasIterOperands());
1782   auto regionArgs = getRegionIterArgs();
1783   auto operands = getIterOperands();
1784   p << regionArgs.front() << " = " << *operands.begin() << ")";
1785   if (regionArgs.size() > 1) {
1786     p << " iter_args(";
1787     llvm::interleaveComma(
1788         llvm::zip(regionArgs.drop_front(), operands.drop_front()), p,
1789         [&](auto it) { p << std::get<0>(it) << " = " << std::get<1>(it); });
1790     p << ") -> (";
1791     llvm::interleaveComma(
1792         llvm::drop_begin(getResultTypes(), getFinalValue() ? 0 : 1), p);
1793     p << ")";
1794   } else if (getFinalValue()) {
1795     p << " -> (" << getResultTypes() << ')';
1796   }
1797   p.printOptionalAttrDictWithKeyword((*this)->getAttrs(),
1798                                      {getFinalValueAttrNameStr()});
1799   p << ' ';
1800   p.printRegion(getRegion(), /*printEntryBlockArgs=*/false,
1801                 /*printBlockTerminators=*/true);
1802 }
1803 
1804 mlir::Region &fir::IterWhileOp::getLoopBody() { return getRegion(); }
1805 
1806 mlir::BlockArgument fir::IterWhileOp::iterArgToBlockArg(mlir::Value iterArg) {
1807   for (auto i : llvm::enumerate(getInitArgs()))
1808     if (iterArg == i.value())
1809       return getRegion().front().getArgument(i.index() + 1);
1810   return {};
1811 }
1812 
1813 void fir::IterWhileOp::resultToSourceOps(
1814     llvm::SmallVectorImpl<mlir::Value> &results, unsigned resultNum) {
1815   auto oper = getFinalValue() ? resultNum + 1 : resultNum;
1816   auto *term = getRegion().front().getTerminator();
1817   if (oper < term->getNumOperands())
1818     results.push_back(term->getOperand(oper));
1819 }
1820 
1821 mlir::Value fir::IterWhileOp::blockArgToSourceOp(unsigned blockArgNum) {
1822   if (blockArgNum > 0 && blockArgNum <= getInitArgs().size())
1823     return getInitArgs()[blockArgNum - 1];
1824   return {};
1825 }
1826 
1827 //===----------------------------------------------------------------------===//
1828 // LenParamIndexOp
1829 //===----------------------------------------------------------------------===//
1830 
1831 mlir::ParseResult fir::LenParamIndexOp::parse(mlir::OpAsmParser &parser,
1832                                               mlir::OperationState &result) {
1833   return parseFieldLikeOp<fir::LenType>(parser, result);
1834 }
1835 
1836 void fir::LenParamIndexOp::print(mlir::OpAsmPrinter &p) {
1837   printFieldLikeOp(p, *this);
1838 }
1839 
1840 void fir::LenParamIndexOp::build(mlir::OpBuilder &builder,
1841                                  mlir::OperationState &result,
1842                                  llvm::StringRef fieldName, mlir::Type recTy,
1843                                  mlir::ValueRange operands) {
1844   result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));
1845   result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));
1846   result.addOperands(operands);
1847 }
1848 
1849 llvm::SmallVector<mlir::Attribute> fir::LenParamIndexOp::getAttributes() {
1850   llvm::SmallVector<mlir::Attribute> attrs;
1851   attrs.push_back(getFieldIdAttr());
1852   attrs.push_back(getOnTypeAttr());
1853   return attrs;
1854 }
1855 
1856 //===----------------------------------------------------------------------===//
1857 // LoadOp
1858 //===----------------------------------------------------------------------===//
1859 
1860 void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
1861                         mlir::Value refVal) {
1862   if (!refVal) {
1863     mlir::emitError(result.location, "LoadOp has null argument");
1864     return;
1865   }
1866   auto eleTy = fir::dyn_cast_ptrEleTy(refVal.getType());
1867   if (!eleTy) {
1868     mlir::emitError(result.location, "not a memory reference type");
1869     return;
1870   }
1871   result.addOperands(refVal);
1872   result.addTypes(eleTy);
1873 }
1874 
1875 mlir::ParseResult fir::LoadOp::getElementOf(mlir::Type &ele, mlir::Type ref) {
1876   if ((ele = fir::dyn_cast_ptrEleTy(ref)))
1877     return mlir::success();
1878   return mlir::failure();
1879 }
1880 
1881 mlir::ParseResult fir::LoadOp::parse(mlir::OpAsmParser &parser,
1882                                      mlir::OperationState &result) {
1883   mlir::Type type;
1884   mlir::OpAsmParser::UnresolvedOperand oper;
1885   if (parser.parseOperand(oper) ||
1886       parser.parseOptionalAttrDict(result.attributes) ||
1887       parser.parseColonType(type) ||
1888       parser.resolveOperand(oper, type, result.operands))
1889     return mlir::failure();
1890   mlir::Type eleTy;
1891   if (fir::LoadOp::getElementOf(eleTy, type) ||
1892       parser.addTypeToList(eleTy, result.types))
1893     return mlir::failure();
1894   return mlir::success();
1895 }
1896 
1897 void fir::LoadOp::print(mlir::OpAsmPrinter &p) {
1898   p << ' ';
1899   p.printOperand(getMemref());
1900   p.printOptionalAttrDict(getOperation()->getAttrs(), {});
1901   p << " : " << getMemref().getType();
1902 }
1903 
1904 //===----------------------------------------------------------------------===//
1905 // DoLoopOp
1906 //===----------------------------------------------------------------------===//
1907 
1908 void fir::DoLoopOp::build(mlir::OpBuilder &builder,
1909                           mlir::OperationState &result, mlir::Value lb,
1910                           mlir::Value ub, mlir::Value step, bool unordered,
1911                           bool finalCountValue, mlir::ValueRange iterArgs,
1912                           llvm::ArrayRef<mlir::NamedAttribute> attributes) {
1913   result.addOperands({lb, ub, step});
1914   result.addOperands(iterArgs);
1915   if (finalCountValue) {
1916     result.addTypes(builder.getIndexType());
1917     result.addAttribute(getFinalValueAttrName(result.name),
1918                         builder.getUnitAttr());
1919   }
1920   for (auto v : iterArgs)
1921     result.addTypes(v.getType());
1922   mlir::Region *bodyRegion = result.addRegion();
1923   bodyRegion->push_back(new mlir::Block{});
1924   if (iterArgs.empty() && !finalCountValue)
1925     fir::DoLoopOp::ensureTerminator(*bodyRegion, builder, result.location);
1926   bodyRegion->front().addArgument(builder.getIndexType(), result.location);
1927   bodyRegion->front().addArguments(
1928       iterArgs.getTypes(),
1929       llvm::SmallVector<mlir::Location>(iterArgs.size(), result.location));
1930   if (unordered)
1931     result.addAttribute(getUnorderedAttrName(result.name),
1932                         builder.getUnitAttr());
1933   result.addAttributes(attributes);
1934 }
1935 
1936 mlir::ParseResult fir::DoLoopOp::parse(mlir::OpAsmParser &parser,
1937                                        mlir::OperationState &result) {
1938   auto &builder = parser.getBuilder();
1939   mlir::OpAsmParser::Argument inductionVariable;
1940   mlir::OpAsmParser::UnresolvedOperand lb, ub, step;
1941   // Parse the induction variable followed by '='.
1942   if (parser.parseArgument(inductionVariable) || parser.parseEqual())
1943     return mlir::failure();
1944 
1945   // Parse loop bounds.
1946   auto indexType = builder.getIndexType();
1947   if (parser.parseOperand(lb) ||
1948       parser.resolveOperand(lb, indexType, result.operands) ||
1949       parser.parseKeyword("to") || parser.parseOperand(ub) ||
1950       parser.resolveOperand(ub, indexType, result.operands) ||
1951       parser.parseKeyword("step") || parser.parseOperand(step) ||
1952       parser.resolveOperand(step, indexType, result.operands))
1953     return mlir::failure();
1954 
1955   if (mlir::succeeded(parser.parseOptionalKeyword("unordered")))
1956     result.addAttribute("unordered", builder.getUnitAttr());
1957 
1958   // Parse the optional initial iteration arguments.
1959   llvm::SmallVector<mlir::OpAsmParser::Argument> regionArgs;
1960   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;
1961   llvm::SmallVector<mlir::Type> argTypes;
1962   bool prependCount = false;
1963   regionArgs.push_back(inductionVariable);
1964 
1965   if (succeeded(parser.parseOptionalKeyword("iter_args"))) {
1966     // Parse assignment list and results type list.
1967     if (parser.parseAssignmentList(regionArgs, operands) ||
1968         parser.parseArrowTypeList(result.types))
1969       return mlir::failure();
1970     if (result.types.size() == operands.size() + 1)
1971       prependCount = true;
1972     // Resolve input operands.
1973     llvm::ArrayRef<mlir::Type> resTypes = result.types;
1974     for (auto operand_type :
1975          llvm::zip(operands, prependCount ? resTypes.drop_front() : resTypes))
1976       if (parser.resolveOperand(std::get<0>(operand_type),
1977                                 std::get<1>(operand_type), result.operands))
1978         return mlir::failure();
1979   } else if (succeeded(parser.parseOptionalArrow())) {
1980     if (parser.parseKeyword("index"))
1981       return mlir::failure();
1982     result.types.push_back(indexType);
1983     prependCount = true;
1984   }
1985 
1986   if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1987     return mlir::failure();
1988 
1989   // Induction variable.
1990   if (prependCount)
1991     result.addAttribute(DoLoopOp::getFinalValueAttrName(result.name),
1992                         builder.getUnitAttr());
1993   else
1994     argTypes.push_back(indexType);
1995   // Loop carried variables
1996   argTypes.append(result.types.begin(), result.types.end());
1997   // Parse the body region.
1998   auto *body = result.addRegion();
1999   if (regionArgs.size() != argTypes.size())
2000     return parser.emitError(
2001         parser.getNameLoc(),
2002         "mismatch in number of loop-carried values and defined values");
2003   for (size_t i = 0, e = regionArgs.size(); i != e; ++i)
2004     regionArgs[i].type = argTypes[i];
2005 
2006   if (parser.parseRegion(*body, regionArgs))
2007     return mlir::failure();
2008 
2009   DoLoopOp::ensureTerminator(*body, builder, result.location);
2010 
2011   return mlir::success();
2012 }
2013 
2014 fir::DoLoopOp fir::getForInductionVarOwner(mlir::Value val) {
2015   auto ivArg = val.dyn_cast<mlir::BlockArgument>();
2016   if (!ivArg)
2017     return {};
2018   assert(ivArg.getOwner() && "unlinked block argument");
2019   auto *containingInst = ivArg.getOwner()->getParentOp();
2020   return mlir::dyn_cast_or_null<fir::DoLoopOp>(containingInst);
2021 }
2022 
2023 // Lifted from loop.loop
2024 mlir::LogicalResult fir::DoLoopOp::verify() {
2025   // Check that the body defines as single block argument for the induction
2026   // variable.
2027   auto *body = getBody();
2028   if (!body->getArgument(0).getType().isIndex())
2029     return emitOpError(
2030         "expected body first argument to be an index argument for "
2031         "the induction variable");
2032 
2033   auto opNumResults = getNumResults();
2034   if (opNumResults == 0)
2035     return mlir::success();
2036 
2037   if (getFinalValue()) {
2038     if (getUnordered())
2039       return emitOpError("unordered loop has no final value");
2040     opNumResults--;
2041   }
2042   if (getNumIterOperands() != opNumResults)
2043     return emitOpError(
2044         "mismatch in number of loop-carried values and defined values");
2045   if (getNumRegionIterArgs() != opNumResults)
2046     return emitOpError(
2047         "mismatch in number of basic block args and defined values");
2048   auto iterOperands = getIterOperands();
2049   auto iterArgs = getRegionIterArgs();
2050   auto opResults = getFinalValue() ? getResults().drop_front() : getResults();
2051   unsigned i = 0u;
2052   for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {
2053     if (std::get<0>(e).getType() != std::get<2>(e).getType())
2054       return emitOpError() << "types mismatch between " << i
2055                            << "th iter operand and defined value";
2056     if (std::get<1>(e).getType() != std::get<2>(e).getType())
2057       return emitOpError() << "types mismatch between " << i
2058                            << "th iter region arg and defined value";
2059 
2060     i++;
2061   }
2062   return mlir::success();
2063 }
2064 
2065 void fir::DoLoopOp::print(mlir::OpAsmPrinter &p) {
2066   bool printBlockTerminators = false;
2067   p << ' ' << getInductionVar() << " = " << getLowerBound() << " to "
2068     << getUpperBound() << " step " << getStep();
2069   if (getUnordered())
2070     p << " unordered";
2071   if (hasIterOperands()) {
2072     p << " iter_args(";
2073     auto regionArgs = getRegionIterArgs();
2074     auto operands = getIterOperands();
2075     llvm::interleaveComma(llvm::zip(regionArgs, operands), p, [&](auto it) {
2076       p << std::get<0>(it) << " = " << std::get<1>(it);
2077     });
2078     p << ") -> (" << getResultTypes() << ')';
2079     printBlockTerminators = true;
2080   } else if (getFinalValue()) {
2081     p << " -> " << getResultTypes();
2082     printBlockTerminators = true;
2083   }
2084   p.printOptionalAttrDictWithKeyword((*this)->getAttrs(),
2085                                      {"unordered", "finalValue"});
2086   p << ' ';
2087   p.printRegion(getRegion(), /*printEntryBlockArgs=*/false,
2088                 printBlockTerminators);
2089 }
2090 
2091 mlir::Region &fir::DoLoopOp::getLoopBody() { return getRegion(); }
2092 
2093 /// Translate a value passed as an iter_arg to the corresponding block
2094 /// argument in the body of the loop.
2095 mlir::BlockArgument fir::DoLoopOp::iterArgToBlockArg(mlir::Value iterArg) {
2096   for (auto i : llvm::enumerate(getInitArgs()))
2097     if (iterArg == i.value())
2098       return getRegion().front().getArgument(i.index() + 1);
2099   return {};
2100 }
2101 
2102 /// Translate the result vector (by index number) to the corresponding value
2103 /// to the `fir.result` Op.
2104 void fir::DoLoopOp::resultToSourceOps(
2105     llvm::SmallVectorImpl<mlir::Value> &results, unsigned resultNum) {
2106   auto oper = getFinalValue() ? resultNum + 1 : resultNum;
2107   auto *term = getRegion().front().getTerminator();
2108   if (oper < term->getNumOperands())
2109     results.push_back(term->getOperand(oper));
2110 }
2111 
2112 /// Translate the block argument (by index number) to the corresponding value
2113 /// passed as an iter_arg to the parent DoLoopOp.
2114 mlir::Value fir::DoLoopOp::blockArgToSourceOp(unsigned blockArgNum) {
2115   if (blockArgNum > 0 && blockArgNum <= getInitArgs().size())
2116     return getInitArgs()[blockArgNum - 1];
2117   return {};
2118 }
2119 
2120 //===----------------------------------------------------------------------===//
2121 // DTEntryOp
2122 //===----------------------------------------------------------------------===//
2123 
2124 mlir::ParseResult fir::DTEntryOp::parse(mlir::OpAsmParser &parser,
2125                                         mlir::OperationState &result) {
2126   llvm::StringRef methodName;
2127   // allow `methodName` or `"methodName"`
2128   if (failed(parser.parseOptionalKeyword(&methodName))) {
2129     mlir::StringAttr methodAttr;
2130     if (parser.parseAttribute(methodAttr,
2131                               fir::DTEntryOp::getMethodAttrNameStr(),
2132                               result.attributes))
2133       return mlir::failure();
2134   } else {
2135     result.addAttribute(fir::DTEntryOp::getMethodAttrNameStr(),
2136                         parser.getBuilder().getStringAttr(methodName));
2137   }
2138   mlir::SymbolRefAttr calleeAttr;
2139   if (parser.parseComma() ||
2140       parser.parseAttribute(calleeAttr, fir::DTEntryOp::getProcAttrNameStr(),
2141                             result.attributes))
2142     return mlir::failure();
2143   return mlir::success();
2144 }
2145 
2146 void fir::DTEntryOp::print(mlir::OpAsmPrinter &p) {
2147   p << ' ' << getMethodAttr() << ", " << getProcAttr();
2148 }
2149 
2150 //===----------------------------------------------------------------------===//
2151 // ReboxOp
2152 //===----------------------------------------------------------------------===//
2153 
2154 /// Get the scalar type related to a fir.box type.
2155 /// Example: return f32 for !fir.box<!fir.heap<!fir.array<?x?xf32>>.
2156 static mlir::Type getBoxScalarEleTy(mlir::Type boxTy) {
2157   auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(boxTy);
2158   if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
2159     return seqTy.getEleTy();
2160   return eleTy;
2161 }
2162 
2163 /// Get the rank from a !fir.box type
2164 static unsigned getBoxRank(mlir::Type boxTy) {
2165   auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(boxTy);
2166   if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
2167     return seqTy.getDimension();
2168   return 0;
2169 }
2170 
2171 /// Test if \p t1 and \p t2 are compatible character types (if they can
2172 /// represent the same type at runtime).
2173 static bool areCompatibleCharacterTypes(mlir::Type t1, mlir::Type t2) {
2174   auto c1 = t1.dyn_cast<fir::CharacterType>();
2175   auto c2 = t2.dyn_cast<fir::CharacterType>();
2176   if (!c1 || !c2)
2177     return false;
2178   if (c1.hasDynamicLen() || c2.hasDynamicLen())
2179     return true;
2180   return c1.getLen() == c2.getLen();
2181 }
2182 
2183 mlir::LogicalResult fir::ReboxOp::verify() {
2184   auto inputBoxTy = getBox().getType();
2185   if (fir::isa_unknown_size_box(inputBoxTy))
2186     return emitOpError("box operand must not have unknown rank or type");
2187   auto outBoxTy = getType();
2188   if (fir::isa_unknown_size_box(outBoxTy))
2189     return emitOpError("result type must not have unknown rank or type");
2190   auto inputRank = getBoxRank(inputBoxTy);
2191   auto inputEleTy = getBoxScalarEleTy(inputBoxTy);
2192   auto outRank = getBoxRank(outBoxTy);
2193   auto outEleTy = getBoxScalarEleTy(outBoxTy);
2194 
2195   if (auto sliceVal = getSlice()) {
2196     // Slicing case
2197     if (sliceVal.getType().cast<fir::SliceType>().getRank() != inputRank)
2198       return emitOpError("slice operand rank must match box operand rank");
2199     if (auto shapeVal = getShape()) {
2200       if (auto shiftTy = shapeVal.getType().dyn_cast<fir::ShiftType>()) {
2201         if (shiftTy.getRank() != inputRank)
2202           return emitOpError("shape operand and input box ranks must match "
2203                              "when there is a slice");
2204       } else {
2205         return emitOpError("shape operand must absent or be a fir.shift "
2206                            "when there is a slice");
2207       }
2208     }
2209     if (auto sliceOp = sliceVal.getDefiningOp()) {
2210       auto slicedRank = mlir::cast<fir::SliceOp>(sliceOp).getOutRank();
2211       if (slicedRank != outRank)
2212         return emitOpError("result type rank and rank after applying slice "
2213                            "operand must match");
2214     }
2215   } else {
2216     // Reshaping case
2217     unsigned shapeRank = inputRank;
2218     if (auto shapeVal = getShape()) {
2219       auto ty = shapeVal.getType();
2220       if (auto shapeTy = ty.dyn_cast<fir::ShapeType>()) {
2221         shapeRank = shapeTy.getRank();
2222       } else if (auto shapeShiftTy = ty.dyn_cast<fir::ShapeShiftType>()) {
2223         shapeRank = shapeShiftTy.getRank();
2224       } else {
2225         auto shiftTy = ty.cast<fir::ShiftType>();
2226         shapeRank = shiftTy.getRank();
2227         if (shapeRank != inputRank)
2228           return emitOpError("shape operand and input box ranks must match "
2229                              "when the shape is a fir.shift");
2230       }
2231     }
2232     if (shapeRank != outRank)
2233       return emitOpError("result type and shape operand ranks must match");
2234   }
2235 
2236   if (inputEleTy != outEleTy) {
2237     // TODO: check that outBoxTy is a parent type of inputBoxTy for derived
2238     // types.
2239     // Character input and output types with constant length may be different if
2240     // there is a substring in the slice, otherwise, they must match. If any of
2241     // the types is a character with dynamic length, the other type can be any
2242     // character type.
2243     const bool typeCanMismatch =
2244         inputEleTy.isa<fir::RecordType>() ||
2245         (getSlice() && inputEleTy.isa<fir::CharacterType>()) ||
2246         areCompatibleCharacterTypes(inputEleTy, outEleTy);
2247     if (!typeCanMismatch)
2248       return emitOpError(
2249           "op input and output element types must match for intrinsic types");
2250   }
2251   return mlir::success();
2252 }
2253 
2254 //===----------------------------------------------------------------------===//
2255 // ResultOp
2256 //===----------------------------------------------------------------------===//
2257 
2258 mlir::LogicalResult fir::ResultOp::verify() {
2259   auto *parentOp = (*this)->getParentOp();
2260   auto results = parentOp->getResults();
2261   auto operands = (*this)->getOperands();
2262 
2263   if (parentOp->getNumResults() != getNumOperands())
2264     return emitOpError() << "parent of result must have same arity";
2265   for (auto e : llvm::zip(results, operands))
2266     if (std::get<0>(e).getType() != std::get<1>(e).getType())
2267       return emitOpError() << "types mismatch between result op and its parent";
2268   return mlir::success();
2269 }
2270 
2271 //===----------------------------------------------------------------------===//
2272 // SaveResultOp
2273 //===----------------------------------------------------------------------===//
2274 
2275 mlir::LogicalResult fir::SaveResultOp::verify() {
2276   auto resultType = getValue().getType();
2277   if (resultType != fir::dyn_cast_ptrEleTy(getMemref().getType()))
2278     return emitOpError("value type must match memory reference type");
2279   if (fir::isa_unknown_size_box(resultType))
2280     return emitOpError("cannot save !fir.box of unknown rank or type");
2281 
2282   if (resultType.isa<fir::BoxType>()) {
2283     if (getShape() || !getTypeparams().empty())
2284       return emitOpError(
2285           "must not have shape or length operands if the value is a fir.box");
2286     return mlir::success();
2287   }
2288 
2289   // fir.record or fir.array case.
2290   unsigned shapeTyRank = 0;
2291   if (auto shapeVal = getShape()) {
2292     auto shapeTy = shapeVal.getType();
2293     if (auto s = shapeTy.dyn_cast<fir::ShapeType>())
2294       shapeTyRank = s.getRank();
2295     else
2296       shapeTyRank = shapeTy.cast<fir::ShapeShiftType>().getRank();
2297   }
2298 
2299   auto eleTy = resultType;
2300   if (auto seqTy = resultType.dyn_cast<fir::SequenceType>()) {
2301     if (seqTy.getDimension() != shapeTyRank)
2302       emitOpError("shape operand must be provided and have the value rank "
2303                   "when the value is a fir.array");
2304     eleTy = seqTy.getEleTy();
2305   } else {
2306     if (shapeTyRank != 0)
2307       emitOpError(
2308           "shape operand should only be provided if the value is a fir.array");
2309   }
2310 
2311   if (auto recTy = eleTy.dyn_cast<fir::RecordType>()) {
2312     if (recTy.getNumLenParams() != getTypeparams().size())
2313       emitOpError("length parameters number must match with the value type "
2314                   "length parameters");
2315   } else if (auto charTy = eleTy.dyn_cast<fir::CharacterType>()) {
2316     if (getTypeparams().size() > 1)
2317       emitOpError("no more than one length parameter must be provided for "
2318                   "character value");
2319   } else {
2320     if (!getTypeparams().empty())
2321       emitOpError("length parameters must not be provided for this value type");
2322   }
2323 
2324   return mlir::success();
2325 }
2326 
2327 //===----------------------------------------------------------------------===//
2328 // IntegralSwitchTerminator
2329 //===----------------------------------------------------------------------===//
2330 static constexpr llvm::StringRef getCompareOffsetAttr() {
2331   return "compare_operand_offsets";
2332 }
2333 
2334 static constexpr llvm::StringRef getTargetOffsetAttr() {
2335   return "target_operand_offsets";
2336 }
2337 
2338 template <typename OpT>
2339 static mlir::LogicalResult verifyIntegralSwitchTerminator(OpT op) {
2340   if (!op.getSelector()
2341            .getType()
2342            .template isa<mlir::IntegerType, mlir::IndexType,
2343                          fir::IntegerType>())
2344     return op.emitOpError("must be an integer");
2345   auto cases =
2346       op->template getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr()).getValue();
2347   auto count = op.getNumDest();
2348   if (count == 0)
2349     return op.emitOpError("must have at least one successor");
2350   if (op.getNumConditions() != count)
2351     return op.emitOpError("number of cases and targets don't match");
2352   if (op.targetOffsetSize() != count)
2353     return op.emitOpError("incorrect number of successor operand groups");
2354   for (decltype(count) i = 0; i != count; ++i) {
2355     if (!cases[i].template isa<mlir::IntegerAttr, mlir::UnitAttr>())
2356       return op.emitOpError("invalid case alternative");
2357   }
2358   return mlir::success();
2359 }
2360 
2361 static mlir::ParseResult parseIntegralSwitchTerminator(
2362     mlir::OpAsmParser &parser, mlir::OperationState &result,
2363     llvm::StringRef casesAttr, llvm::StringRef operandSegmentAttr) {
2364   mlir::OpAsmParser::UnresolvedOperand selector;
2365   mlir::Type type;
2366   if (fir::parseSelector(parser, result, selector, type))
2367     return mlir::failure();
2368 
2369   llvm::SmallVector<mlir::Attribute> ivalues;
2370   llvm::SmallVector<mlir::Block *> dests;
2371   llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;
2372   while (true) {
2373     mlir::Attribute ivalue; // Integer or Unit
2374     mlir::Block *dest;
2375     llvm::SmallVector<mlir::Value> destArg;
2376     mlir::NamedAttrList temp;
2377     if (parser.parseAttribute(ivalue, "i", temp) || parser.parseComma() ||
2378         parser.parseSuccessorAndUseList(dest, destArg))
2379       return mlir::failure();
2380     ivalues.push_back(ivalue);
2381     dests.push_back(dest);
2382     destArgs.push_back(destArg);
2383     if (!parser.parseOptionalRSquare())
2384       break;
2385     if (parser.parseComma())
2386       return mlir::failure();
2387   }
2388   auto &bld = parser.getBuilder();
2389   result.addAttribute(casesAttr, bld.getArrayAttr(ivalues));
2390   llvm::SmallVector<int32_t> argOffs;
2391   int32_t sumArgs = 0;
2392   const auto count = dests.size();
2393   for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
2394     result.addSuccessors(dests[i]);
2395     result.addOperands(destArgs[i]);
2396     auto argSize = destArgs[i].size();
2397     argOffs.push_back(argSize);
2398     sumArgs += argSize;
2399   }
2400   result.addAttribute(operandSegmentAttr,
2401                       bld.getI32VectorAttr({1, 0, sumArgs}));
2402   result.addAttribute(getTargetOffsetAttr(), bld.getI32VectorAttr(argOffs));
2403   return mlir::success();
2404 }
2405 
2406 template <typename OpT>
2407 static void printIntegralSwitchTerminator(OpT op, mlir::OpAsmPrinter &p) {
2408   p << ' ';
2409   p.printOperand(op.getSelector());
2410   p << " : " << op.getSelector().getType() << " [";
2411   auto cases =
2412       op->template getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr()).getValue();
2413   auto count = op.getNumConditions();
2414   for (decltype(count) i = 0; i != count; ++i) {
2415     if (i)
2416       p << ", ";
2417     auto &attr = cases[i];
2418     if (auto intAttr = attr.template dyn_cast_or_null<mlir::IntegerAttr>())
2419       p << intAttr.getValue();
2420     else
2421       p.printAttribute(attr);
2422     p << ", ";
2423     op.printSuccessorAtIndex(p, i);
2424   }
2425   p << ']';
2426   p.printOptionalAttrDict(
2427       op->getAttrs(), {op.getCasesAttr(), getCompareOffsetAttr(),
2428                        getTargetOffsetAttr(), op.getOperandSegmentSizeAttr()});
2429 }
2430 
2431 //===----------------------------------------------------------------------===//
2432 // SelectOp
2433 //===----------------------------------------------------------------------===//
2434 
2435 mlir::LogicalResult fir::SelectOp::verify() {
2436   return verifyIntegralSwitchTerminator(*this);
2437 }
2438 
2439 mlir::ParseResult fir::SelectOp::parse(mlir::OpAsmParser &parser,
2440                                        mlir::OperationState &result) {
2441   return parseIntegralSwitchTerminator(parser, result, getCasesAttr(),
2442                                        getOperandSegmentSizeAttr());
2443 }
2444 
2445 void fir::SelectOp::print(mlir::OpAsmPrinter &p) {
2446   printIntegralSwitchTerminator(*this, p);
2447 }
2448 
2449 template <typename A, typename... AdditionalArgs>
2450 static A getSubOperands(unsigned pos, A allArgs,
2451                         mlir::DenseIntElementsAttr ranges,
2452                         AdditionalArgs &&...additionalArgs) {
2453   unsigned start = 0;
2454   for (unsigned i = 0; i < pos; ++i)
2455     start += (*(ranges.begin() + i)).getZExtValue();
2456   return allArgs.slice(start, (*(ranges.begin() + pos)).getZExtValue(),
2457                        std::forward<AdditionalArgs>(additionalArgs)...);
2458 }
2459 
2460 static mlir::MutableOperandRange
2461 getMutableSuccessorOperands(unsigned pos, mlir::MutableOperandRange operands,
2462                             llvm::StringRef offsetAttr) {
2463   mlir::Operation *owner = operands.getOwner();
2464   mlir::NamedAttribute targetOffsetAttr =
2465       *owner->getAttrDictionary().getNamed(offsetAttr);
2466   return getSubOperands(
2467       pos, operands,
2468       targetOffsetAttr.getValue().cast<mlir::DenseIntElementsAttr>(),
2469       mlir::MutableOperandRange::OperandSegment(pos, targetOffsetAttr));
2470 }
2471 
2472 static unsigned denseElementsSize(mlir::DenseIntElementsAttr attr) {
2473   return attr.getNumElements();
2474 }
2475 
2476 llvm::Optional<mlir::OperandRange> fir::SelectOp::getCompareOperands(unsigned) {
2477   return {};
2478 }
2479 
2480 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2481 fir::SelectOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {
2482   return {};
2483 }
2484 
2485 mlir::SuccessorOperands fir::SelectOp::getSuccessorOperands(unsigned oper) {
2486   return mlir::SuccessorOperands(::getMutableSuccessorOperands(
2487       oper, getTargetArgsMutable(), getTargetOffsetAttr()));
2488 }
2489 
2490 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2491 fir::SelectOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
2492                                     unsigned oper) {
2493   auto a =
2494       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2495   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2496       getOperandSegmentSizeAttr());
2497   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2498 }
2499 
2500 llvm::Optional<mlir::ValueRange>
2501 fir::SelectOp::getSuccessorOperands(mlir::ValueRange operands, unsigned oper) {
2502   auto a =
2503       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2504   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2505       getOperandSegmentSizeAttr());
2506   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2507 }
2508 
2509 unsigned fir::SelectOp::targetOffsetSize() {
2510   return denseElementsSize((*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2511       getTargetOffsetAttr()));
2512 }
2513 
2514 //===----------------------------------------------------------------------===//
2515 // SelectCaseOp
2516 //===----------------------------------------------------------------------===//
2517 
2518 llvm::Optional<mlir::OperandRange>
2519 fir::SelectCaseOp::getCompareOperands(unsigned cond) {
2520   auto a = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2521       getCompareOffsetAttr());
2522   return {getSubOperands(cond, getCompareArgs(), a)};
2523 }
2524 
2525 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2526 fir::SelectCaseOp::getCompareOperands(llvm::ArrayRef<mlir::Value> operands,
2527                                       unsigned cond) {
2528   auto a = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2529       getCompareOffsetAttr());
2530   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2531       getOperandSegmentSizeAttr());
2532   return {getSubOperands(cond, getSubOperands(1, operands, segments), a)};
2533 }
2534 
2535 llvm::Optional<mlir::ValueRange>
2536 fir::SelectCaseOp::getCompareOperands(mlir::ValueRange operands,
2537                                       unsigned cond) {
2538   auto a = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2539       getCompareOffsetAttr());
2540   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2541       getOperandSegmentSizeAttr());
2542   return {getSubOperands(cond, getSubOperands(1, operands, segments), a)};
2543 }
2544 
2545 mlir::SuccessorOperands fir::SelectCaseOp::getSuccessorOperands(unsigned oper) {
2546   return mlir::SuccessorOperands(::getMutableSuccessorOperands(
2547       oper, getTargetArgsMutable(), getTargetOffsetAttr()));
2548 }
2549 
2550 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2551 fir::SelectCaseOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
2552                                         unsigned oper) {
2553   auto a =
2554       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2555   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2556       getOperandSegmentSizeAttr());
2557   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2558 }
2559 
2560 llvm::Optional<mlir::ValueRange>
2561 fir::SelectCaseOp::getSuccessorOperands(mlir::ValueRange operands,
2562                                         unsigned oper) {
2563   auto a =
2564       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2565   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2566       getOperandSegmentSizeAttr());
2567   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2568 }
2569 
2570 // parser for fir.select_case Op
2571 mlir::ParseResult fir::SelectCaseOp::parse(mlir::OpAsmParser &parser,
2572                                            mlir::OperationState &result) {
2573   mlir::OpAsmParser::UnresolvedOperand selector;
2574   mlir::Type type;
2575   if (fir::parseSelector(parser, result, selector, type))
2576     return mlir::failure();
2577 
2578   llvm::SmallVector<mlir::Attribute> attrs;
2579   llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> opers;
2580   llvm::SmallVector<mlir::Block *> dests;
2581   llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;
2582   llvm::SmallVector<std::int32_t> argOffs;
2583   std::int32_t offSize = 0;
2584   while (true) {
2585     mlir::Attribute attr;
2586     mlir::Block *dest;
2587     llvm::SmallVector<mlir::Value> destArg;
2588     mlir::NamedAttrList temp;
2589     if (parser.parseAttribute(attr, "a", temp) || isValidCaseAttr(attr) ||
2590         parser.parseComma())
2591       return mlir::failure();
2592     attrs.push_back(attr);
2593     if (attr.dyn_cast_or_null<mlir::UnitAttr>()) {
2594       argOffs.push_back(0);
2595     } else if (attr.dyn_cast_or_null<fir::ClosedIntervalAttr>()) {
2596       mlir::OpAsmParser::UnresolvedOperand oper1;
2597       mlir::OpAsmParser::UnresolvedOperand oper2;
2598       if (parser.parseOperand(oper1) || parser.parseComma() ||
2599           parser.parseOperand(oper2) || parser.parseComma())
2600         return mlir::failure();
2601       opers.push_back(oper1);
2602       opers.push_back(oper2);
2603       argOffs.push_back(2);
2604       offSize += 2;
2605     } else {
2606       mlir::OpAsmParser::UnresolvedOperand oper;
2607       if (parser.parseOperand(oper) || parser.parseComma())
2608         return mlir::failure();
2609       opers.push_back(oper);
2610       argOffs.push_back(1);
2611       ++offSize;
2612     }
2613     if (parser.parseSuccessorAndUseList(dest, destArg))
2614       return mlir::failure();
2615     dests.push_back(dest);
2616     destArgs.push_back(destArg);
2617     if (mlir::succeeded(parser.parseOptionalRSquare()))
2618       break;
2619     if (parser.parseComma())
2620       return mlir::failure();
2621   }
2622   result.addAttribute(fir::SelectCaseOp::getCasesAttr(),
2623                       parser.getBuilder().getArrayAttr(attrs));
2624   if (parser.resolveOperands(opers, type, result.operands))
2625     return mlir::failure();
2626   llvm::SmallVector<int32_t> targOffs;
2627   int32_t toffSize = 0;
2628   const auto count = dests.size();
2629   for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
2630     result.addSuccessors(dests[i]);
2631     result.addOperands(destArgs[i]);
2632     auto argSize = destArgs[i].size();
2633     targOffs.push_back(argSize);
2634     toffSize += argSize;
2635   }
2636   auto &bld = parser.getBuilder();
2637   result.addAttribute(fir::SelectCaseOp::getOperandSegmentSizeAttr(),
2638                       bld.getI32VectorAttr({1, offSize, toffSize}));
2639   result.addAttribute(getCompareOffsetAttr(), bld.getI32VectorAttr(argOffs));
2640   result.addAttribute(getTargetOffsetAttr(), bld.getI32VectorAttr(targOffs));
2641   return mlir::success();
2642 }
2643 
2644 void fir::SelectCaseOp::print(mlir::OpAsmPrinter &p) {
2645   p << ' ';
2646   p.printOperand(getSelector());
2647   p << " : " << getSelector().getType() << " [";
2648   auto cases =
2649       getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
2650   auto count = getNumConditions();
2651   for (decltype(count) i = 0; i != count; ++i) {
2652     if (i)
2653       p << ", ";
2654     p << cases[i] << ", ";
2655     if (!cases[i].isa<mlir::UnitAttr>()) {
2656       auto caseArgs = *getCompareOperands(i);
2657       p.printOperand(*caseArgs.begin());
2658       p << ", ";
2659       if (cases[i].isa<fir::ClosedIntervalAttr>()) {
2660         p.printOperand(*(++caseArgs.begin()));
2661         p << ", ";
2662       }
2663     }
2664     printSuccessorAtIndex(p, i);
2665   }
2666   p << ']';
2667   p.printOptionalAttrDict(getOperation()->getAttrs(),
2668                           {getCasesAttr(), getCompareOffsetAttr(),
2669                            getTargetOffsetAttr(), getOperandSegmentSizeAttr()});
2670 }
2671 
2672 unsigned fir::SelectCaseOp::compareOffsetSize() {
2673   return denseElementsSize((*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2674       getCompareOffsetAttr()));
2675 }
2676 
2677 unsigned fir::SelectCaseOp::targetOffsetSize() {
2678   return denseElementsSize((*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2679       getTargetOffsetAttr()));
2680 }
2681 
2682 void fir::SelectCaseOp::build(mlir::OpBuilder &builder,
2683                               mlir::OperationState &result,
2684                               mlir::Value selector,
2685                               llvm::ArrayRef<mlir::Attribute> compareAttrs,
2686                               llvm::ArrayRef<mlir::ValueRange> cmpOperands,
2687                               llvm::ArrayRef<mlir::Block *> destinations,
2688                               llvm::ArrayRef<mlir::ValueRange> destOperands,
2689                               llvm::ArrayRef<mlir::NamedAttribute> attributes) {
2690   result.addOperands(selector);
2691   result.addAttribute(getCasesAttr(), builder.getArrayAttr(compareAttrs));
2692   llvm::SmallVector<int32_t> operOffs;
2693   int32_t operSize = 0;
2694   for (auto attr : compareAttrs) {
2695     if (attr.isa<fir::ClosedIntervalAttr>()) {
2696       operOffs.push_back(2);
2697       operSize += 2;
2698     } else if (attr.isa<mlir::UnitAttr>()) {
2699       operOffs.push_back(0);
2700     } else {
2701       operOffs.push_back(1);
2702       ++operSize;
2703     }
2704   }
2705   for (auto ops : cmpOperands)
2706     result.addOperands(ops);
2707   result.addAttribute(getCompareOffsetAttr(),
2708                       builder.getI32VectorAttr(operOffs));
2709   const auto count = destinations.size();
2710   for (auto d : destinations)
2711     result.addSuccessors(d);
2712   const auto opCount = destOperands.size();
2713   llvm::SmallVector<std::int32_t> argOffs;
2714   std::int32_t sumArgs = 0;
2715   for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
2716     if (i < opCount) {
2717       result.addOperands(destOperands[i]);
2718       const auto argSz = destOperands[i].size();
2719       argOffs.push_back(argSz);
2720       sumArgs += argSz;
2721     } else {
2722       argOffs.push_back(0);
2723     }
2724   }
2725   result.addAttribute(getOperandSegmentSizeAttr(),
2726                       builder.getI32VectorAttr({1, operSize, sumArgs}));
2727   result.addAttribute(getTargetOffsetAttr(), builder.getI32VectorAttr(argOffs));
2728   result.addAttributes(attributes);
2729 }
2730 
2731 /// This builder has a slightly simplified interface in that the list of
2732 /// operands need not be partitioned by the builder. Instead the operands are
2733 /// partitioned here, before being passed to the default builder. This
2734 /// partitioning is unchecked, so can go awry on bad input.
2735 void fir::SelectCaseOp::build(mlir::OpBuilder &builder,
2736                               mlir::OperationState &result,
2737                               mlir::Value selector,
2738                               llvm::ArrayRef<mlir::Attribute> compareAttrs,
2739                               llvm::ArrayRef<mlir::Value> cmpOpList,
2740                               llvm::ArrayRef<mlir::Block *> destinations,
2741                               llvm::ArrayRef<mlir::ValueRange> destOperands,
2742                               llvm::ArrayRef<mlir::NamedAttribute> attributes) {
2743   llvm::SmallVector<mlir::ValueRange> cmpOpers;
2744   auto iter = cmpOpList.begin();
2745   for (auto &attr : compareAttrs) {
2746     if (attr.isa<fir::ClosedIntervalAttr>()) {
2747       cmpOpers.push_back(mlir::ValueRange({iter, iter + 2}));
2748       iter += 2;
2749     } else if (attr.isa<mlir::UnitAttr>()) {
2750       cmpOpers.push_back(mlir::ValueRange{});
2751     } else {
2752       cmpOpers.push_back(mlir::ValueRange({iter, iter + 1}));
2753       ++iter;
2754     }
2755   }
2756   build(builder, result, selector, compareAttrs, cmpOpers, destinations,
2757         destOperands, attributes);
2758 }
2759 
2760 mlir::LogicalResult fir::SelectCaseOp::verify() {
2761   if (!getSelector()
2762            .getType()
2763            .isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType,
2764                 fir::LogicalType, fir::CharacterType>())
2765     return emitOpError("must be an integer, character, or logical");
2766   auto cases =
2767       getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
2768   auto count = getNumDest();
2769   if (count == 0)
2770     return emitOpError("must have at least one successor");
2771   if (getNumConditions() != count)
2772     return emitOpError("number of conditions and successors don't match");
2773   if (compareOffsetSize() != count)
2774     return emitOpError("incorrect number of compare operand groups");
2775   if (targetOffsetSize() != count)
2776     return emitOpError("incorrect number of successor operand groups");
2777   for (decltype(count) i = 0; i != count; ++i) {
2778     auto &attr = cases[i];
2779     if (!(attr.isa<fir::PointIntervalAttr>() ||
2780           attr.isa<fir::LowerBoundAttr>() || attr.isa<fir::UpperBoundAttr>() ||
2781           attr.isa<fir::ClosedIntervalAttr>() || attr.isa<mlir::UnitAttr>()))
2782       return emitOpError("incorrect select case attribute type");
2783   }
2784   return mlir::success();
2785 }
2786 
2787 //===----------------------------------------------------------------------===//
2788 // SelectRankOp
2789 //===----------------------------------------------------------------------===//
2790 
2791 mlir::LogicalResult fir::SelectRankOp::verify() {
2792   return verifyIntegralSwitchTerminator(*this);
2793 }
2794 
2795 mlir::ParseResult fir::SelectRankOp::parse(mlir::OpAsmParser &parser,
2796                                            mlir::OperationState &result) {
2797   return parseIntegralSwitchTerminator(parser, result, getCasesAttr(),
2798                                        getOperandSegmentSizeAttr());
2799 }
2800 
2801 void fir::SelectRankOp::print(mlir::OpAsmPrinter &p) {
2802   printIntegralSwitchTerminator(*this, p);
2803 }
2804 
2805 llvm::Optional<mlir::OperandRange>
2806 fir::SelectRankOp::getCompareOperands(unsigned) {
2807   return {};
2808 }
2809 
2810 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2811 fir::SelectRankOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {
2812   return {};
2813 }
2814 
2815 mlir::SuccessorOperands fir::SelectRankOp::getSuccessorOperands(unsigned oper) {
2816   return mlir::SuccessorOperands(::getMutableSuccessorOperands(
2817       oper, getTargetArgsMutable(), getTargetOffsetAttr()));
2818 }
2819 
2820 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2821 fir::SelectRankOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
2822                                         unsigned oper) {
2823   auto a =
2824       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2825   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2826       getOperandSegmentSizeAttr());
2827   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2828 }
2829 
2830 llvm::Optional<mlir::ValueRange>
2831 fir::SelectRankOp::getSuccessorOperands(mlir::ValueRange operands,
2832                                         unsigned oper) {
2833   auto a =
2834       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2835   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2836       getOperandSegmentSizeAttr());
2837   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2838 }
2839 
2840 unsigned fir::SelectRankOp::targetOffsetSize() {
2841   return denseElementsSize((*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2842       getTargetOffsetAttr()));
2843 }
2844 
2845 //===----------------------------------------------------------------------===//
2846 // SelectTypeOp
2847 //===----------------------------------------------------------------------===//
2848 
2849 llvm::Optional<mlir::OperandRange>
2850 fir::SelectTypeOp::getCompareOperands(unsigned) {
2851   return {};
2852 }
2853 
2854 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2855 fir::SelectTypeOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {
2856   return {};
2857 }
2858 
2859 mlir::SuccessorOperands fir::SelectTypeOp::getSuccessorOperands(unsigned oper) {
2860   return mlir::SuccessorOperands(::getMutableSuccessorOperands(
2861       oper, getTargetArgsMutable(), getTargetOffsetAttr()));
2862 }
2863 
2864 llvm::Optional<llvm::ArrayRef<mlir::Value>>
2865 fir::SelectTypeOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,
2866                                         unsigned oper) {
2867   auto a =
2868       (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(getTargetOffsetAttr());
2869   auto segments = (*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2870       getOperandSegmentSizeAttr());
2871   return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};
2872 }
2873 
2874 mlir::ParseResult fir::SelectTypeOp::parse(mlir::OpAsmParser &parser,
2875                                            mlir::OperationState &result) {
2876   mlir::OpAsmParser::UnresolvedOperand selector;
2877   mlir::Type type;
2878   if (fir::parseSelector(parser, result, selector, type))
2879     return mlir::failure();
2880 
2881   llvm::SmallVector<mlir::Attribute> attrs;
2882   llvm::SmallVector<mlir::Block *> dests;
2883   llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;
2884   while (true) {
2885     mlir::Attribute attr;
2886     mlir::Block *dest;
2887     llvm::SmallVector<mlir::Value> destArg;
2888     mlir::NamedAttrList temp;
2889     if (parser.parseAttribute(attr, "a", temp) || parser.parseComma() ||
2890         parser.parseSuccessorAndUseList(dest, destArg))
2891       return mlir::failure();
2892     attrs.push_back(attr);
2893     dests.push_back(dest);
2894     destArgs.push_back(destArg);
2895     if (mlir::succeeded(parser.parseOptionalRSquare()))
2896       break;
2897     if (parser.parseComma())
2898       return mlir::failure();
2899   }
2900   auto &bld = parser.getBuilder();
2901   result.addAttribute(fir::SelectTypeOp::getCasesAttr(),
2902                       bld.getArrayAttr(attrs));
2903   llvm::SmallVector<int32_t> argOffs;
2904   int32_t offSize = 0;
2905   const auto count = dests.size();
2906   for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
2907     result.addSuccessors(dests[i]);
2908     result.addOperands(destArgs[i]);
2909     auto argSize = destArgs[i].size();
2910     argOffs.push_back(argSize);
2911     offSize += argSize;
2912   }
2913   result.addAttribute(fir::SelectTypeOp::getOperandSegmentSizeAttr(),
2914                       bld.getI32VectorAttr({1, 0, offSize}));
2915   result.addAttribute(getTargetOffsetAttr(), bld.getI32VectorAttr(argOffs));
2916   return mlir::success();
2917 }
2918 
2919 unsigned fir::SelectTypeOp::targetOffsetSize() {
2920   return denseElementsSize((*this)->getAttrOfType<mlir::DenseIntElementsAttr>(
2921       getTargetOffsetAttr()));
2922 }
2923 
2924 void fir::SelectTypeOp::print(mlir::OpAsmPrinter &p) {
2925   p << ' ';
2926   p.printOperand(getSelector());
2927   p << " : " << getSelector().getType() << " [";
2928   auto cases =
2929       getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
2930   auto count = getNumConditions();
2931   for (decltype(count) i = 0; i != count; ++i) {
2932     if (i)
2933       p << ", ";
2934     p << cases[i] << ", ";
2935     printSuccessorAtIndex(p, i);
2936   }
2937   p << ']';
2938   p.printOptionalAttrDict(getOperation()->getAttrs(),
2939                           {getCasesAttr(), getCompareOffsetAttr(),
2940                            getTargetOffsetAttr(),
2941                            fir::SelectTypeOp::getOperandSegmentSizeAttr()});
2942 }
2943 
2944 mlir::LogicalResult fir::SelectTypeOp::verify() {
2945   if (!(getSelector().getType().isa<fir::BoxType>()))
2946     return emitOpError("must be a boxed type");
2947   auto cases =
2948       getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();
2949   auto count = getNumDest();
2950   if (count == 0)
2951     return emitOpError("must have at least one successor");
2952   if (getNumConditions() != count)
2953     return emitOpError("number of conditions and successors don't match");
2954   if (targetOffsetSize() != count)
2955     return emitOpError("incorrect number of successor operand groups");
2956   for (decltype(count) i = 0; i != count; ++i) {
2957     auto &attr = cases[i];
2958     if (!(attr.isa<fir::ExactTypeAttr>() || attr.isa<fir::SubclassAttr>() ||
2959           attr.isa<mlir::UnitAttr>()))
2960       return emitOpError("invalid type-case alternative");
2961   }
2962   return mlir::success();
2963 }
2964 
2965 void fir::SelectTypeOp::build(mlir::OpBuilder &builder,
2966                               mlir::OperationState &result,
2967                               mlir::Value selector,
2968                               llvm::ArrayRef<mlir::Attribute> typeOperands,
2969                               llvm::ArrayRef<mlir::Block *> destinations,
2970                               llvm::ArrayRef<mlir::ValueRange> destOperands,
2971                               llvm::ArrayRef<mlir::NamedAttribute> attributes) {
2972   result.addOperands(selector);
2973   result.addAttribute(getCasesAttr(), builder.getArrayAttr(typeOperands));
2974   const auto count = destinations.size();
2975   for (mlir::Block *dest : destinations)
2976     result.addSuccessors(dest);
2977   const auto opCount = destOperands.size();
2978   llvm::SmallVector<int32_t> argOffs;
2979   int32_t sumArgs = 0;
2980   for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {
2981     if (i < opCount) {
2982       result.addOperands(destOperands[i]);
2983       const auto argSz = destOperands[i].size();
2984       argOffs.push_back(argSz);
2985       sumArgs += argSz;
2986     } else {
2987       argOffs.push_back(0);
2988     }
2989   }
2990   result.addAttribute(getOperandSegmentSizeAttr(),
2991                       builder.getI32VectorAttr({1, 0, sumArgs}));
2992   result.addAttribute(getTargetOffsetAttr(), builder.getI32VectorAttr(argOffs));
2993   result.addAttributes(attributes);
2994 }
2995 
2996 //===----------------------------------------------------------------------===//
2997 // ShapeOp
2998 //===----------------------------------------------------------------------===//
2999 
3000 mlir::LogicalResult fir::ShapeOp::verify() {
3001   auto size = getExtents().size();
3002   auto shapeTy = getType().dyn_cast<fir::ShapeType>();
3003   assert(shapeTy && "must be a shape type");
3004   if (shapeTy.getRank() != size)
3005     return emitOpError("shape type rank mismatch");
3006   return mlir::success();
3007 }
3008 
3009 //===----------------------------------------------------------------------===//
3010 // ShapeShiftOp
3011 //===----------------------------------------------------------------------===//
3012 
3013 mlir::LogicalResult fir::ShapeShiftOp::verify() {
3014   auto size = getPairs().size();
3015   if (size < 2 || size > 16 * 2)
3016     return emitOpError("incorrect number of args");
3017   if (size % 2 != 0)
3018     return emitOpError("requires a multiple of 2 args");
3019   auto shapeTy = getType().dyn_cast<fir::ShapeShiftType>();
3020   assert(shapeTy && "must be a shape shift type");
3021   if (shapeTy.getRank() * 2 != size)
3022     return emitOpError("shape type rank mismatch");
3023   return mlir::success();
3024 }
3025 
3026 //===----------------------------------------------------------------------===//
3027 // ShiftOp
3028 //===----------------------------------------------------------------------===//
3029 
3030 mlir::LogicalResult fir::ShiftOp::verify() {
3031   auto size = getOrigins().size();
3032   auto shiftTy = getType().dyn_cast<fir::ShiftType>();
3033   assert(shiftTy && "must be a shift type");
3034   if (shiftTy.getRank() != size)
3035     return emitOpError("shift type rank mismatch");
3036   return mlir::success();
3037 }
3038 
3039 //===----------------------------------------------------------------------===//
3040 // SliceOp
3041 //===----------------------------------------------------------------------===//
3042 
3043 void fir::SliceOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3044                          mlir::ValueRange trips, mlir::ValueRange path,
3045                          mlir::ValueRange substr) {
3046   const auto rank = trips.size() / 3;
3047   auto sliceTy = fir::SliceType::get(builder.getContext(), rank);
3048   build(builder, result, sliceTy, trips, path, substr);
3049 }
3050 
3051 /// Return the output rank of a slice op. The output rank must be between 1 and
3052 /// the rank of the array being sliced (inclusive).
3053 unsigned fir::SliceOp::getOutputRank(mlir::ValueRange triples) {
3054   unsigned rank = 0;
3055   if (!triples.empty()) {
3056     for (unsigned i = 1, end = triples.size(); i < end; i += 3) {
3057       auto *op = triples[i].getDefiningOp();
3058       if (!mlir::isa_and_nonnull<fir::UndefOp>(op))
3059         ++rank;
3060     }
3061     assert(rank > 0);
3062   }
3063   return rank;
3064 }
3065 
3066 mlir::LogicalResult fir::SliceOp::verify() {
3067   auto size = getTriples().size();
3068   if (size < 3 || size > 16 * 3)
3069     return emitOpError("incorrect number of args for triple");
3070   if (size % 3 != 0)
3071     return emitOpError("requires a multiple of 3 args");
3072   auto sliceTy = getType().dyn_cast<fir::SliceType>();
3073   assert(sliceTy && "must be a slice type");
3074   if (sliceTy.getRank() * 3 != size)
3075     return emitOpError("slice type rank mismatch");
3076   return mlir::success();
3077 }
3078 
3079 //===----------------------------------------------------------------------===//
3080 // StoreOp
3081 //===----------------------------------------------------------------------===//
3082 
3083 mlir::Type fir::StoreOp::elementType(mlir::Type refType) {
3084   return fir::dyn_cast_ptrEleTy(refType);
3085 }
3086 
3087 mlir::ParseResult fir::StoreOp::parse(mlir::OpAsmParser &parser,
3088                                       mlir::OperationState &result) {
3089   mlir::Type type;
3090   mlir::OpAsmParser::UnresolvedOperand oper;
3091   mlir::OpAsmParser::UnresolvedOperand store;
3092   if (parser.parseOperand(oper) || parser.parseKeyword("to") ||
3093       parser.parseOperand(store) ||
3094       parser.parseOptionalAttrDict(result.attributes) ||
3095       parser.parseColonType(type) ||
3096       parser.resolveOperand(oper, fir::StoreOp::elementType(type),
3097                             result.operands) ||
3098       parser.resolveOperand(store, type, result.operands))
3099     return mlir::failure();
3100   return mlir::success();
3101 }
3102 
3103 void fir::StoreOp::print(mlir::OpAsmPrinter &p) {
3104   p << ' ';
3105   p.printOperand(getValue());
3106   p << " to ";
3107   p.printOperand(getMemref());
3108   p.printOptionalAttrDict(getOperation()->getAttrs(), {});
3109   p << " : " << getMemref().getType();
3110 }
3111 
3112 mlir::LogicalResult fir::StoreOp::verify() {
3113   if (getValue().getType() != fir::dyn_cast_ptrEleTy(getMemref().getType()))
3114     return emitOpError("store value type must match memory reference type");
3115   if (fir::isa_unknown_size_box(getValue().getType()))
3116     return emitOpError("cannot store !fir.box of unknown rank or type");
3117   return mlir::success();
3118 }
3119 
3120 //===----------------------------------------------------------------------===//
3121 // StringLitOp
3122 //===----------------------------------------------------------------------===//
3123 
3124 bool fir::StringLitOp::isWideValue() {
3125   auto eleTy = getType().cast<fir::SequenceType>().getEleTy();
3126   return eleTy.cast<fir::CharacterType>().getFKind() != 1;
3127 }
3128 
3129 static mlir::NamedAttribute
3130 mkNamedIntegerAttr(mlir::OpBuilder &builder, llvm::StringRef name, int64_t v) {
3131   assert(v > 0);
3132   return builder.getNamedAttr(
3133       name, builder.getIntegerAttr(builder.getIntegerType(64), v));
3134 }
3135 
3136 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3137                              mlir::OperationState &result,
3138                              fir::CharacterType inType, llvm::StringRef val,
3139                              llvm::Optional<int64_t> len) {
3140   auto valAttr = builder.getNamedAttr(value(), builder.getStringAttr(val));
3141   int64_t length = len ? *len : inType.getLen();
3142   auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3143   result.addAttributes({valAttr, lenAttr});
3144   result.addTypes(inType);
3145 }
3146 
3147 template <typename C>
3148 static mlir::ArrayAttr convertToArrayAttr(mlir::OpBuilder &builder,
3149                                           llvm::ArrayRef<C> xlist) {
3150   llvm::SmallVector<mlir::Attribute> attrs;
3151   auto ty = builder.getIntegerType(8 * sizeof(C));
3152   for (auto ch : xlist)
3153     attrs.push_back(builder.getIntegerAttr(ty, ch));
3154   return builder.getArrayAttr(attrs);
3155 }
3156 
3157 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3158                              mlir::OperationState &result,
3159                              fir::CharacterType inType,
3160                              llvm::ArrayRef<char> vlist,
3161                              llvm::Optional<std::int64_t> len) {
3162   auto valAttr =
3163       builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));
3164   std::int64_t length = len ? *len : inType.getLen();
3165   auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3166   result.addAttributes({valAttr, lenAttr});
3167   result.addTypes(inType);
3168 }
3169 
3170 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3171                              mlir::OperationState &result,
3172                              fir::CharacterType inType,
3173                              llvm::ArrayRef<char16_t> vlist,
3174                              llvm::Optional<std::int64_t> len) {
3175   auto valAttr =
3176       builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));
3177   std::int64_t length = len ? *len : inType.getLen();
3178   auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3179   result.addAttributes({valAttr, lenAttr});
3180   result.addTypes(inType);
3181 }
3182 
3183 void fir::StringLitOp::build(mlir::OpBuilder &builder,
3184                              mlir::OperationState &result,
3185                              fir::CharacterType inType,
3186                              llvm::ArrayRef<char32_t> vlist,
3187                              llvm::Optional<std::int64_t> len) {
3188   auto valAttr =
3189       builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));
3190   std::int64_t length = len ? *len : inType.getLen();
3191   auto lenAttr = mkNamedIntegerAttr(builder, size(), length);
3192   result.addAttributes({valAttr, lenAttr});
3193   result.addTypes(inType);
3194 }
3195 
3196 mlir::ParseResult fir::StringLitOp::parse(mlir::OpAsmParser &parser,
3197                                           mlir::OperationState &result) {
3198   auto &builder = parser.getBuilder();
3199   mlir::Attribute val;
3200   mlir::NamedAttrList attrs;
3201   llvm::SMLoc trailingTypeLoc;
3202   if (parser.parseAttribute(val, "fake", attrs))
3203     return mlir::failure();
3204   if (auto v = val.dyn_cast<mlir::StringAttr>())
3205     result.attributes.push_back(
3206         builder.getNamedAttr(fir::StringLitOp::value(), v));
3207   else if (auto v = val.dyn_cast<mlir::ArrayAttr>())
3208     result.attributes.push_back(
3209         builder.getNamedAttr(fir::StringLitOp::xlist(), v));
3210   else
3211     return parser.emitError(parser.getCurrentLocation(),
3212                             "found an invalid constant");
3213   mlir::IntegerAttr sz;
3214   mlir::Type type;
3215   if (parser.parseLParen() ||
3216       parser.parseAttribute(sz, fir::StringLitOp::size(), result.attributes) ||
3217       parser.parseRParen() || parser.getCurrentLocation(&trailingTypeLoc) ||
3218       parser.parseColonType(type))
3219     return mlir::failure();
3220   auto charTy = type.dyn_cast<fir::CharacterType>();
3221   if (!charTy)
3222     return parser.emitError(trailingTypeLoc, "must have character type");
3223   type = fir::CharacterType::get(builder.getContext(), charTy.getFKind(),
3224                                  sz.getInt());
3225   if (!type || parser.addTypesToList(type, result.types))
3226     return mlir::failure();
3227   return mlir::success();
3228 }
3229 
3230 void fir::StringLitOp::print(mlir::OpAsmPrinter &p) {
3231   p << ' ' << getValue() << '(';
3232   p << getSize().cast<mlir::IntegerAttr>().getValue() << ") : ";
3233   p.printType(getType());
3234 }
3235 
3236 mlir::LogicalResult fir::StringLitOp::verify() {
3237   if (getSize().cast<mlir::IntegerAttr>().getValue().isNegative())
3238     return emitOpError("size must be non-negative");
3239   if (auto xl = getOperation()->getAttr(fir::StringLitOp::xlist())) {
3240     auto xList = xl.cast<mlir::ArrayAttr>();
3241     for (auto a : xList)
3242       if (!a.isa<mlir::IntegerAttr>())
3243         return emitOpError("values in list must be integers");
3244   }
3245   return mlir::success();
3246 }
3247 
3248 //===----------------------------------------------------------------------===//
3249 // UnboxProcOp
3250 //===----------------------------------------------------------------------===//
3251 
3252 mlir::LogicalResult fir::UnboxProcOp::verify() {
3253   if (auto eleTy = fir::dyn_cast_ptrEleTy(getRefTuple().getType()))
3254     if (eleTy.isa<mlir::TupleType>())
3255       return mlir::success();
3256   return emitOpError("second output argument has bad type");
3257 }
3258 
3259 //===----------------------------------------------------------------------===//
3260 // IfOp
3261 //===----------------------------------------------------------------------===//
3262 
3263 void fir::IfOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3264                       mlir::Value cond, bool withElseRegion) {
3265   build(builder, result, llvm::None, cond, withElseRegion);
3266 }
3267 
3268 void fir::IfOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,
3269                       mlir::TypeRange resultTypes, mlir::Value cond,
3270                       bool withElseRegion) {
3271   result.addOperands(cond);
3272   result.addTypes(resultTypes);
3273 
3274   mlir::Region *thenRegion = result.addRegion();
3275   thenRegion->push_back(new mlir::Block());
3276   if (resultTypes.empty())
3277     IfOp::ensureTerminator(*thenRegion, builder, result.location);
3278 
3279   mlir::Region *elseRegion = result.addRegion();
3280   if (withElseRegion) {
3281     elseRegion->push_back(new mlir::Block());
3282     if (resultTypes.empty())
3283       IfOp::ensureTerminator(*elseRegion, builder, result.location);
3284   }
3285 }
3286 
3287 mlir::ParseResult fir::IfOp::parse(mlir::OpAsmParser &parser,
3288                                    mlir::OperationState &result) {
3289   result.regions.reserve(2);
3290   mlir::Region *thenRegion = result.addRegion();
3291   mlir::Region *elseRegion = result.addRegion();
3292 
3293   auto &builder = parser.getBuilder();
3294   mlir::OpAsmParser::UnresolvedOperand cond;
3295   mlir::Type i1Type = builder.getIntegerType(1);
3296   if (parser.parseOperand(cond) ||
3297       parser.resolveOperand(cond, i1Type, result.operands))
3298     return mlir::failure();
3299 
3300   if (parser.parseOptionalArrowTypeList(result.types))
3301     return mlir::failure();
3302 
3303   if (parser.parseRegion(*thenRegion, {}, {}))
3304     return mlir::failure();
3305   fir::IfOp::ensureTerminator(*thenRegion, parser.getBuilder(),
3306                               result.location);
3307 
3308   if (mlir::succeeded(parser.parseOptionalKeyword("else"))) {
3309     if (parser.parseRegion(*elseRegion, {}, {}))
3310       return mlir::failure();
3311     fir::IfOp::ensureTerminator(*elseRegion, parser.getBuilder(),
3312                                 result.location);
3313   }
3314 
3315   // Parse the optional attribute list.
3316   if (parser.parseOptionalAttrDict(result.attributes))
3317     return mlir::failure();
3318   return mlir::success();
3319 }
3320 
3321 mlir::LogicalResult fir::IfOp::verify() {
3322   if (getNumResults() != 0 && getElseRegion().empty())
3323     return emitOpError("must have an else block if defining values");
3324 
3325   return mlir::success();
3326 }
3327 
3328 void fir::IfOp::print(mlir::OpAsmPrinter &p) {
3329   bool printBlockTerminators = false;
3330   p << ' ' << getCondition();
3331   if (!getResults().empty()) {
3332     p << " -> (" << getResultTypes() << ')';
3333     printBlockTerminators = true;
3334   }
3335   p << ' ';
3336   p.printRegion(getThenRegion(), /*printEntryBlockArgs=*/false,
3337                 printBlockTerminators);
3338 
3339   // Print the 'else' regions if it exists and has a block.
3340   auto &otherReg = getElseRegion();
3341   if (!otherReg.empty()) {
3342     p << " else ";
3343     p.printRegion(otherReg, /*printEntryBlockArgs=*/false,
3344                   printBlockTerminators);
3345   }
3346   p.printOptionalAttrDict((*this)->getAttrs());
3347 }
3348 
3349 void fir::IfOp::resultToSourceOps(llvm::SmallVectorImpl<mlir::Value> &results,
3350                                   unsigned resultNum) {
3351   auto *term = getThenRegion().front().getTerminator();
3352   if (resultNum < term->getNumOperands())
3353     results.push_back(term->getOperand(resultNum));
3354   term = getElseRegion().front().getTerminator();
3355   if (resultNum < term->getNumOperands())
3356     results.push_back(term->getOperand(resultNum));
3357 }
3358 
3359 //===----------------------------------------------------------------------===//
3360 
3361 mlir::ParseResult fir::isValidCaseAttr(mlir::Attribute attr) {
3362   if (attr.isa<mlir::UnitAttr, fir::ClosedIntervalAttr, fir::PointIntervalAttr,
3363                fir::LowerBoundAttr, fir::UpperBoundAttr>())
3364     return mlir::success();
3365   return mlir::failure();
3366 }
3367 
3368 unsigned fir::getCaseArgumentOffset(llvm::ArrayRef<mlir::Attribute> cases,
3369                                     unsigned dest) {
3370   unsigned o = 0;
3371   for (unsigned i = 0; i < dest; ++i) {
3372     auto &attr = cases[i];
3373     if (!attr.dyn_cast_or_null<mlir::UnitAttr>()) {
3374       ++o;
3375       if (attr.dyn_cast_or_null<fir::ClosedIntervalAttr>())
3376         ++o;
3377     }
3378   }
3379   return o;
3380 }
3381 
3382 mlir::ParseResult
3383 fir::parseSelector(mlir::OpAsmParser &parser, mlir::OperationState &result,
3384                    mlir::OpAsmParser::UnresolvedOperand &selector,
3385                    mlir::Type &type) {
3386   if (parser.parseOperand(selector) || parser.parseColonType(type) ||
3387       parser.resolveOperand(selector, type, result.operands) ||
3388       parser.parseLSquare())
3389     return mlir::failure();
3390   return mlir::success();
3391 }
3392 
3393 mlir::func::FuncOp
3394 fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module,
3395                   llvm::StringRef name, mlir::FunctionType type,
3396                   llvm::ArrayRef<mlir::NamedAttribute> attrs) {
3397   if (auto f = module.lookupSymbol<mlir::func::FuncOp>(name))
3398     return f;
3399   mlir::OpBuilder modBuilder(module.getBodyRegion());
3400   modBuilder.setInsertionPointToEnd(module.getBody());
3401   auto result = modBuilder.create<mlir::func::FuncOp>(loc, name, type, attrs);
3402   result.setVisibility(mlir::SymbolTable::Visibility::Private);
3403   return result;
3404 }
3405 
3406 fir::GlobalOp fir::createGlobalOp(mlir::Location loc, mlir::ModuleOp module,
3407                                   llvm::StringRef name, mlir::Type type,
3408                                   llvm::ArrayRef<mlir::NamedAttribute> attrs) {
3409   if (auto g = module.lookupSymbol<fir::GlobalOp>(name))
3410     return g;
3411   mlir::OpBuilder modBuilder(module.getBodyRegion());
3412   auto result = modBuilder.create<fir::GlobalOp>(loc, name, type, attrs);
3413   result.setVisibility(mlir::SymbolTable::Visibility::Private);
3414   return result;
3415 }
3416 
3417 bool fir::hasHostAssociationArgument(mlir::func::FuncOp func) {
3418   if (auto allArgAttrs = func.getAllArgAttrs())
3419     for (auto attr : allArgAttrs)
3420       if (auto dict = attr.template dyn_cast_or_null<mlir::DictionaryAttr>())
3421         if (dict.get(fir::getHostAssocAttrName()))
3422           return true;
3423   return false;
3424 }
3425 
3426 bool fir::valueHasFirAttribute(mlir::Value value,
3427                                llvm::StringRef attributeName) {
3428   // If this is a fir.box that was loaded, the fir attributes will be on the
3429   // related fir.ref<fir.box> creation.
3430   if (value.getType().isa<fir::BoxType>())
3431     if (auto definingOp = value.getDefiningOp())
3432       if (auto loadOp = mlir::dyn_cast<fir::LoadOp>(definingOp))
3433         value = loadOp.getMemref();
3434   // If this is a function argument, look in the argument attributes.
3435   if (auto blockArg = value.dyn_cast<mlir::BlockArgument>()) {
3436     if (blockArg.getOwner() && blockArg.getOwner()->isEntryBlock())
3437       if (auto funcOp = mlir::dyn_cast<mlir::func::FuncOp>(
3438               blockArg.getOwner()->getParentOp()))
3439         if (funcOp.getArgAttr(blockArg.getArgNumber(), attributeName))
3440           return true;
3441     return false;
3442   }
3443 
3444   if (auto definingOp = value.getDefiningOp()) {
3445     // If this is an allocated value, look at the allocation attributes.
3446     if (mlir::isa<fir::AllocMemOp>(definingOp) ||
3447         mlir::isa<AllocaOp>(definingOp))
3448       return definingOp->hasAttr(attributeName);
3449     // If this is an imported global, look at AddrOfOp and GlobalOp attributes.
3450     // Both operations are looked at because use/host associated variable (the
3451     // AddrOfOp) can have ASYNCHRONOUS/VOLATILE attributes even if the ultimate
3452     // entity (the globalOp) does not have them.
3453     if (auto addressOfOp = mlir::dyn_cast<fir::AddrOfOp>(definingOp)) {
3454       if (addressOfOp->hasAttr(attributeName))
3455         return true;
3456       if (auto module = definingOp->getParentOfType<mlir::ModuleOp>())
3457         if (auto globalOp =
3458                 module.lookupSymbol<fir::GlobalOp>(addressOfOp.getSymbol()))
3459           return globalOp->hasAttr(attributeName);
3460     }
3461   }
3462   // TODO: Construct associated entities attributes. Decide where the fir
3463   // attributes must be placed/looked for in this case.
3464   return false;
3465 }
3466 
3467 bool fir::anyFuncArgsHaveAttr(mlir::func::FuncOp func, llvm::StringRef attr) {
3468   for (unsigned i = 0, end = func.getNumArguments(); i < end; ++i)
3469     if (func.getArgAttr(i, attr))
3470       return true;
3471   return false;
3472 }
3473 
3474 mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {
3475   for (auto i = path.begin(), end = path.end(); eleTy && i < end;) {
3476     eleTy = llvm::TypeSwitch<mlir::Type, mlir::Type>(eleTy)
3477                 .Case<fir::RecordType>([&](fir::RecordType ty) {
3478                   if (auto *op = (*i++).getDefiningOp()) {
3479                     if (auto off = mlir::dyn_cast<fir::FieldIndexOp>(op))
3480                       return ty.getType(off.getFieldName());
3481                     if (auto off = mlir::dyn_cast<mlir::arith::ConstantOp>(op))
3482                       return ty.getType(fir::toInt(off));
3483                   }
3484                   return mlir::Type{};
3485                 })
3486                 .Case<fir::SequenceType>([&](fir::SequenceType ty) {
3487                   bool valid = true;
3488                   const auto rank = ty.getDimension();
3489                   for (std::remove_const_t<decltype(rank)> ii = 0;
3490                        valid && ii < rank; ++ii)
3491                     valid = i < end && fir::isa_integer((*i++).getType());
3492                   return valid ? ty.getEleTy() : mlir::Type{};
3493                 })
3494                 .Case<mlir::TupleType>([&](mlir::TupleType ty) {
3495                   if (auto *op = (*i++).getDefiningOp())
3496                     if (auto off = mlir::dyn_cast<mlir::arith::ConstantOp>(op))
3497                       return ty.getType(fir::toInt(off));
3498                   return mlir::Type{};
3499                 })
3500                 .Case<fir::ComplexType>([&](fir::ComplexType ty) {
3501                   auto x = *i;
3502                   if (auto *op = (*i++).getDefiningOp())
3503                     if (fir::isa_integer(x.getType()))
3504                       return ty.getEleType(fir::getKindMapping(
3505                           op->getParentOfType<mlir::ModuleOp>()));
3506                   return mlir::Type{};
3507                 })
3508                 .Case<mlir::ComplexType>([&](mlir::ComplexType ty) {
3509                   if (fir::isa_integer((*i++).getType()))
3510                     return ty.getElementType();
3511                   return mlir::Type{};
3512                 })
3513                 .Default([&](const auto &) { return mlir::Type{}; });
3514   }
3515   return eleTy;
3516 }
3517 
3518 // Tablegen operators
3519 
3520 #define GET_OP_CLASSES
3521 #include "flang/Optimizer/Dialect/FIROps.cpp.inc"
3522