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