xref: /llvm-project/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp (revision c4891089125d4ba312204cc9a666339abbfc4db2)
1 //===-- HLFIROps.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/HLFIR/HLFIROps.h"
14 
15 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
16 #include "flang/Optimizer/Dialect/FIRType.h"
17 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
18 #include "flang/Optimizer/HLFIR/HLFIRDialect.h"
19 #include "mlir/IR/Builders.h"
20 #include "mlir/IR/BuiltinAttributes.h"
21 #include "mlir/IR/BuiltinTypes.h"
22 #include "mlir/IR/DialectImplementation.h"
23 #include "mlir/IR/Matchers.h"
24 #include "mlir/IR/OpImplementation.h"
25 #include "llvm/ADT/APInt.h"
26 #include "llvm/ADT/TypeSwitch.h"
27 #include "llvm/Support/CommandLine.h"
28 #include <iterator>
29 #include <mlir/Interfaces/SideEffectInterfaces.h>
30 #include <optional>
31 #include <tuple>
32 
33 static llvm::cl::opt<bool> useStrictIntrinsicVerifier(
34     "strict-intrinsic-verifier", llvm::cl::init(false),
35     llvm::cl::desc("use stricter verifier for HLFIR intrinsic operations"));
36 
37 /// generic implementation of the memory side effects interface for hlfir
38 /// transformational intrinsic operations
39 static void
40 getIntrinsicEffects(mlir::Operation *self,
41                     llvm::SmallVectorImpl<mlir::SideEffects::EffectInstance<
42                         mlir::MemoryEffects::Effect>> &effects) {
43   // allocation effect if we return an expr
44   assert(self->getNumResults() == 1 &&
45          "hlfir intrinsic ops only produce 1 result");
46   if (mlir::isa<hlfir::ExprType>(self->getResult(0).getType()))
47     effects.emplace_back(mlir::MemoryEffects::Allocate::get(),
48                          self->getOpResult(0),
49                          mlir::SideEffects::DefaultResource::get());
50 
51   // read effect if we read from a pointer or refference type
52   // or a box who'se pointer is read from inside of the intrinsic so that
53   // loop conflicts can be detected in code like
54   // hlfir.region_assign {
55   //   %2 = hlfir.transpose %0#0 : (!fir.box<!fir.array<?x?xf32>>) ->
56   //   !hlfir.expr<?x?xf32> hlfir.yield %2 : !hlfir.expr<?x?xf32> cleanup {
57   //     hlfir.destroy %2 : !hlfir.expr<?x?xf32>
58   //   }
59   // } to {
60   //   hlfir.yield %0#0 : !fir.box<!fir.array<?x?xf32>>
61   // }
62   for (mlir::OpOperand &operand : self->getOpOperands()) {
63     mlir::Type opTy = operand.get().getType();
64     if (fir::isa_ref_type(opTy) || fir::isa_box_type(opTy))
65       effects.emplace_back(mlir::MemoryEffects::Read::get(), &operand,
66                            mlir::SideEffects::DefaultResource::get());
67   }
68 }
69 
70 /// Verification helper for checking if two types are the same.
71 /// Set \p allowCharacterLenMismatch to true, if character types
72 /// of different known lengths should be treated as the same.
73 template <typename Op>
74 static llvm::LogicalResult areMatchingTypes(Op &op, mlir::Type type1,
75                                             mlir::Type type2,
76                                             bool allowCharacterLenMismatch) {
77   if (auto charType1 = mlir::dyn_cast<fir::CharacterType>(type1))
78     if (auto charType2 = mlir::dyn_cast<fir::CharacterType>(type2)) {
79       // Character kinds must match.
80       if (charType1.getFKind() != charType2.getFKind())
81         return op.emitOpError("character KIND mismatch");
82 
83       // Constant propagation can result in mismatching lengths
84       // in the dead code, but we should not fail on this.
85       if (!allowCharacterLenMismatch)
86         if (charType1.getLen() != fir::CharacterType::unknownLen() &&
87             charType2.getLen() != fir::CharacterType::unknownLen() &&
88             charType1.getLen() != charType2.getLen())
89           return op.emitOpError("character LEN mismatch");
90 
91       return mlir::success();
92     }
93 
94   return type1 == type2 ? mlir::success() : mlir::failure();
95 }
96 
97 //===----------------------------------------------------------------------===//
98 // DeclareOp
99 //===----------------------------------------------------------------------===//
100 
101 /// Is this a fir.[ref/ptr/heap]<fir.[box/class]<fir.heap<T>>> type?
102 static bool isAllocatableBoxRef(mlir::Type type) {
103   fir::BaseBoxType boxType =
104       mlir::dyn_cast_or_null<fir::BaseBoxType>(fir::dyn_cast_ptrEleTy(type));
105   return boxType && mlir::isa<fir::HeapType>(boxType.getEleTy());
106 }
107 
108 llvm::LogicalResult hlfir::AssignOp::verify() {
109   mlir::Type lhsType = getLhs().getType();
110   if (isAllocatableAssignment() && !isAllocatableBoxRef(lhsType))
111     return emitOpError("lhs must be an allocatable when `realloc` is set");
112   if (mustKeepLhsLengthInAllocatableAssignment() &&
113       !(isAllocatableAssignment() &&
114         mlir::isa<fir::CharacterType>(hlfir::getFortranElementType(lhsType))))
115     return emitOpError("`realloc` must be set and lhs must be a character "
116                        "allocatable when `keep_lhs_length_if_realloc` is set");
117   return mlir::success();
118 }
119 
120 void hlfir::AssignOp::getEffects(
121     llvm::SmallVectorImpl<
122         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
123         &effects) {
124   mlir::OpOperand &rhs = getRhsMutable();
125   mlir::OpOperand &lhs = getLhsMutable();
126   mlir::Type rhsType = getRhs().getType();
127   mlir::Type lhsType = getLhs().getType();
128   if (mlir::isa<fir::RecordType>(hlfir::getFortranElementType(lhsType))) {
129     // For derived type assignments, set unknown read/write effects since it
130     // is not known here if user defined finalization is needed, and also
131     // because allocatable components may lead to "deeper" read/write effects
132     // that cannot be described with this API.
133     effects.emplace_back(mlir::MemoryEffects::Read::get(),
134                          mlir::SideEffects::DefaultResource::get());
135     effects.emplace_back(mlir::MemoryEffects::Write::get(),
136                          mlir::SideEffects::DefaultResource::get());
137   } else {
138     // Read effect when RHS is a variable.
139     if (hlfir::isFortranVariableType(rhsType)) {
140       if (hlfir::isBoxAddressType(rhsType)) {
141         // Unknown read effect if the RHS is a descriptor since the read effect
142         // on the data cannot be described.
143         effects.emplace_back(mlir::MemoryEffects::Read::get(),
144                              mlir::SideEffects::DefaultResource::get());
145       } else {
146         effects.emplace_back(mlir::MemoryEffects::Read::get(), &rhs,
147                              mlir::SideEffects::DefaultResource::get());
148       }
149     }
150 
151     // Write effects on LHS.
152     if (hlfir::isBoxAddressType(lhsType)) {
153       //  If the LHS is a descriptor, the descriptor will be read and the data
154       //  write cannot be described in this API (and the descriptor may be
155       //  written to in case of realloc, which is covered by the unknown write
156       //  effect.
157       effects.emplace_back(mlir::MemoryEffects::Read::get(), &lhs,
158                            mlir::SideEffects::DefaultResource::get());
159       effects.emplace_back(mlir::MemoryEffects::Write::get(),
160                            mlir::SideEffects::DefaultResource::get());
161     } else {
162       effects.emplace_back(mlir::MemoryEffects::Write::get(), &lhs,
163                            mlir::SideEffects::DefaultResource::get());
164     }
165   }
166 
167   if (getRealloc()) {
168     // Reallocation of the data cannot be precisely described by this API.
169     effects.emplace_back(mlir::MemoryEffects::Free::get(),
170                          mlir::SideEffects::DefaultResource::get());
171     effects.emplace_back(mlir::MemoryEffects::Allocate::get(),
172                          mlir::SideEffects::DefaultResource::get());
173   }
174 }
175 
176 //===----------------------------------------------------------------------===//
177 // DeclareOp
178 //===----------------------------------------------------------------------===//
179 
180 /// Given a FIR memory type, and information about non default lower bounds, get
181 /// the related HLFIR variable type.
182 mlir::Type hlfir::DeclareOp::getHLFIRVariableType(mlir::Type inputType,
183                                                   bool hasExplicitLowerBounds) {
184   mlir::Type type = fir::unwrapRefType(inputType);
185   if (mlir::isa<fir::BaseBoxType>(type))
186     return inputType;
187   if (auto charType = mlir::dyn_cast<fir::CharacterType>(type))
188     if (charType.hasDynamicLen())
189       return fir::BoxCharType::get(charType.getContext(), charType.getFKind());
190 
191   auto seqType = mlir::dyn_cast<fir::SequenceType>(type);
192   bool hasDynamicExtents =
193       seqType && fir::sequenceWithNonConstantShape(seqType);
194   mlir::Type eleType = seqType ? seqType.getEleTy() : type;
195   bool hasDynamicLengthParams = fir::characterWithDynamicLen(eleType) ||
196                                 fir::isRecordWithTypeParameters(eleType);
197   if (hasExplicitLowerBounds || hasDynamicExtents || hasDynamicLengthParams)
198     return fir::BoxType::get(type);
199   return inputType;
200 }
201 
202 static bool hasExplicitLowerBounds(mlir::Value shape) {
203   return shape &&
204          mlir::isa<fir::ShapeShiftType, fir::ShiftType>(shape.getType());
205 }
206 
207 void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
208                              mlir::OperationState &result, mlir::Value memref,
209                              llvm::StringRef uniq_name, mlir::Value shape,
210                              mlir::ValueRange typeparams,
211                              mlir::Value dummy_scope,
212                              fir::FortranVariableFlagsAttr fortran_attrs,
213                              cuf::DataAttributeAttr data_attr) {
214   auto nameAttr = builder.getStringAttr(uniq_name);
215   mlir::Type inputType = memref.getType();
216   bool hasExplicitLbs = hasExplicitLowerBounds(shape);
217   mlir::Type hlfirVariableType =
218       getHLFIRVariableType(inputType, hasExplicitLbs);
219   build(builder, result, {hlfirVariableType, inputType}, memref, shape,
220         typeparams, dummy_scope, nameAttr, fortran_attrs, data_attr);
221 }
222 
223 llvm::LogicalResult hlfir::DeclareOp::verify() {
224   if (getMemref().getType() != getResult(1).getType())
225     return emitOpError("second result type must match input memref type");
226   mlir::Type hlfirVariableType = getHLFIRVariableType(
227       getMemref().getType(), hasExplicitLowerBounds(getShape()));
228   if (hlfirVariableType != getResult(0).getType())
229     return emitOpError("first result type is inconsistent with variable "
230                        "properties: expected ")
231            << hlfirVariableType;
232   // The rest of the argument verification is done by the
233   // FortranVariableInterface verifier.
234   auto fortranVar =
235       mlir::cast<fir::FortranVariableOpInterface>(this->getOperation());
236   return fortranVar.verifyDeclareLikeOpImpl(getMemref());
237 }
238 
239 //===----------------------------------------------------------------------===//
240 // DesignateOp
241 //===----------------------------------------------------------------------===//
242 
243 void hlfir::DesignateOp::build(
244     mlir::OpBuilder &builder, mlir::OperationState &result,
245     mlir::Type result_type, mlir::Value memref, llvm::StringRef component,
246     mlir::Value component_shape, llvm::ArrayRef<Subscript> subscripts,
247     mlir::ValueRange substring, std::optional<bool> complex_part,
248     mlir::Value shape, mlir::ValueRange typeparams,
249     fir::FortranVariableFlagsAttr fortran_attrs) {
250   auto componentAttr =
251       component.empty() ? mlir::StringAttr{} : builder.getStringAttr(component);
252   llvm::SmallVector<mlir::Value> indices;
253   llvm::SmallVector<bool> isTriplet;
254   for (auto subscript : subscripts) {
255     if (auto *triplet = std::get_if<Triplet>(&subscript)) {
256       isTriplet.push_back(true);
257       indices.push_back(std::get<0>(*triplet));
258       indices.push_back(std::get<1>(*triplet));
259       indices.push_back(std::get<2>(*triplet));
260     } else {
261       isTriplet.push_back(false);
262       indices.push_back(std::get<mlir::Value>(subscript));
263     }
264   }
265   auto isTripletAttr =
266       mlir::DenseBoolArrayAttr::get(builder.getContext(), isTriplet);
267   auto complexPartAttr =
268       complex_part.has_value()
269           ? mlir::BoolAttr::get(builder.getContext(), *complex_part)
270           : mlir::BoolAttr{};
271   build(builder, result, result_type, memref, componentAttr, component_shape,
272         indices, isTripletAttr, substring, complexPartAttr, shape, typeparams,
273         fortran_attrs);
274 }
275 
276 void hlfir::DesignateOp::build(mlir::OpBuilder &builder,
277                                mlir::OperationState &result,
278                                mlir::Type result_type, mlir::Value memref,
279                                mlir::ValueRange indices,
280                                mlir::ValueRange typeparams,
281                                fir::FortranVariableFlagsAttr fortran_attrs) {
282   llvm::SmallVector<bool> isTriplet(indices.size(), false);
283   auto isTripletAttr =
284       mlir::DenseBoolArrayAttr::get(builder.getContext(), isTriplet);
285   build(builder, result, result_type, memref,
286         /*componentAttr=*/mlir::StringAttr{}, /*component_shape=*/mlir::Value{},
287         indices, isTripletAttr, /*substring*/ mlir::ValueRange{},
288         /*complexPartAttr=*/mlir::BoolAttr{}, /*shape=*/mlir::Value{},
289         typeparams, fortran_attrs);
290 }
291 
292 static mlir::ParseResult parseDesignatorIndices(
293     mlir::OpAsmParser &parser,
294     llvm::SmallVectorImpl<mlir::OpAsmParser::UnresolvedOperand> &indices,
295     mlir::DenseBoolArrayAttr &isTripletAttr) {
296   llvm::SmallVector<bool> isTriplet;
297   if (mlir::succeeded(parser.parseOptionalLParen())) {
298     do {
299       mlir::OpAsmParser::UnresolvedOperand i1, i2, i3;
300       if (parser.parseOperand(i1))
301         return mlir::failure();
302       indices.push_back(i1);
303       if (mlir::succeeded(parser.parseOptionalColon())) {
304         if (parser.parseOperand(i2) || parser.parseColon() ||
305             parser.parseOperand(i3))
306           return mlir::failure();
307         indices.push_back(i2);
308         indices.push_back(i3);
309         isTriplet.push_back(true);
310       } else {
311         isTriplet.push_back(false);
312       }
313     } while (mlir::succeeded(parser.parseOptionalComma()));
314     if (parser.parseRParen())
315       return mlir::failure();
316   }
317   isTripletAttr = mlir::DenseBoolArrayAttr::get(parser.getContext(), isTriplet);
318   return mlir::success();
319 }
320 
321 static void
322 printDesignatorIndices(mlir::OpAsmPrinter &p, hlfir::DesignateOp designateOp,
323                        mlir::OperandRange indices,
324                        const mlir::DenseBoolArrayAttr &isTripletAttr) {
325   if (!indices.empty()) {
326     p << '(';
327     unsigned i = 0;
328     for (auto isTriplet : isTripletAttr.asArrayRef()) {
329       if (isTriplet) {
330         assert(i + 2 < indices.size() && "ill-formed indices");
331         p << indices[i] << ":" << indices[i + 1] << ":" << indices[i + 2];
332         i += 3;
333       } else {
334         p << indices[i++];
335       }
336       if (i != indices.size())
337         p << ", ";
338     }
339     p << ')';
340   }
341 }
342 
343 static mlir::ParseResult
344 parseDesignatorComplexPart(mlir::OpAsmParser &parser,
345                            mlir::BoolAttr &complexPart) {
346   if (mlir::succeeded(parser.parseOptionalKeyword("imag")))
347     complexPart = mlir::BoolAttr::get(parser.getContext(), true);
348   else if (mlir::succeeded(parser.parseOptionalKeyword("real")))
349     complexPart = mlir::BoolAttr::get(parser.getContext(), false);
350   return mlir::success();
351 }
352 
353 static void printDesignatorComplexPart(mlir::OpAsmPrinter &p,
354                                        hlfir::DesignateOp designateOp,
355                                        mlir::BoolAttr complexPartAttr) {
356   if (complexPartAttr) {
357     if (complexPartAttr.getValue())
358       p << "imag";
359     else
360       p << "real";
361   }
362 }
363 template <typename Op>
364 static llvm::LogicalResult verifyTypeparams(Op &op, mlir::Type elementType,
365                                             unsigned numLenParam) {
366   if (mlir::isa<fir::CharacterType>(elementType)) {
367     if (numLenParam != 1)
368       return op.emitOpError("must be provided one length parameter when the "
369                             "result is a character");
370   } else if (fir::isRecordWithTypeParameters(elementType)) {
371     if (numLenParam !=
372         mlir::cast<fir::RecordType>(elementType).getNumLenParams())
373       return op.emitOpError("must be provided the same number of length "
374                             "parameters as in the result derived type");
375   } else if (numLenParam != 0) {
376     return op.emitOpError(
377         "must not be provided length parameters if the result "
378         "type does not have length parameters");
379   }
380   return mlir::success();
381 }
382 
383 llvm::LogicalResult hlfir::DesignateOp::verify() {
384   mlir::Type memrefType = getMemref().getType();
385   mlir::Type baseType = getFortranElementOrSequenceType(memrefType);
386   mlir::Type baseElementType = fir::unwrapSequenceType(baseType);
387   unsigned numSubscripts = getIsTriplet().size();
388   unsigned subscriptsRank =
389       llvm::count_if(getIsTriplet(), [](bool isTriplet) { return isTriplet; });
390   unsigned outputRank = 0;
391   mlir::Type outputElementType;
392   bool hasBoxComponent;
393   if (getComponent()) {
394     auto component = getComponent().value();
395     auto recType = mlir::dyn_cast<fir::RecordType>(baseElementType);
396     if (!recType)
397       return emitOpError(
398           "component must be provided only when the memref is a derived type");
399     unsigned fieldIdx = recType.getFieldIndex(component);
400     if (fieldIdx > recType.getNumFields()) {
401       return emitOpError("component ")
402              << component << " is not a component of memref element type "
403              << recType;
404     }
405     mlir::Type fieldType = recType.getType(fieldIdx);
406     mlir::Type componentBaseType = getFortranElementOrSequenceType(fieldType);
407     hasBoxComponent = mlir::isa<fir::BaseBoxType>(fieldType);
408     if (mlir::isa<fir::SequenceType>(componentBaseType) &&
409         mlir::isa<fir::SequenceType>(baseType) &&
410         (numSubscripts == 0 || subscriptsRank > 0))
411       return emitOpError("indices must be provided and must not contain "
412                          "triplets when both memref and component are arrays");
413     if (numSubscripts != 0) {
414       if (!mlir::isa<fir::SequenceType>(componentBaseType))
415         return emitOpError("indices must not be provided if component appears "
416                            "and is not an array component");
417       if (!getComponentShape())
418         return emitOpError(
419             "component_shape must be provided when indexing a component");
420       mlir::Type compShapeType = getComponentShape().getType();
421       unsigned componentRank =
422           mlir::cast<fir::SequenceType>(componentBaseType).getDimension();
423       auto shapeType = mlir::dyn_cast<fir::ShapeType>(compShapeType);
424       auto shapeShiftType = mlir::dyn_cast<fir::ShapeShiftType>(compShapeType);
425       if (!((shapeType && shapeType.getRank() == componentRank) ||
426             (shapeShiftType && shapeShiftType.getRank() == componentRank)))
427         return emitOpError("component_shape must be a fir.shape or "
428                            "fir.shapeshift with the rank of the component");
429       if (numSubscripts > componentRank)
430         return emitOpError("indices number must match array component rank");
431     }
432     if (auto baseSeqType = mlir::dyn_cast<fir::SequenceType>(baseType))
433       // This case must come first to cover "array%array_comp(i, j)" that has
434       // subscripts for the component but whose rank come from the base.
435       outputRank = baseSeqType.getDimension();
436     else if (numSubscripts != 0)
437       outputRank = subscriptsRank;
438     else if (auto componentSeqType =
439                  mlir::dyn_cast<fir::SequenceType>(componentBaseType))
440       outputRank = componentSeqType.getDimension();
441     outputElementType = fir::unwrapSequenceType(componentBaseType);
442   } else {
443     outputElementType = baseElementType;
444     unsigned baseTypeRank =
445         mlir::isa<fir::SequenceType>(baseType)
446             ? mlir::cast<fir::SequenceType>(baseType).getDimension()
447             : 0;
448     if (numSubscripts != 0) {
449       if (baseTypeRank != numSubscripts)
450         return emitOpError("indices number must match memref rank");
451       outputRank = subscriptsRank;
452     } else if (auto baseSeqType = mlir::dyn_cast<fir::SequenceType>(baseType)) {
453       outputRank = baseSeqType.getDimension();
454     }
455   }
456 
457   if (!getSubstring().empty()) {
458     if (!mlir::isa<fir::CharacterType>(outputElementType))
459       return emitOpError("memref or component must have character type if "
460                          "substring indices are provided");
461     if (getSubstring().size() != 2)
462       return emitOpError("substring must contain 2 indices when provided");
463   }
464   if (getComplexPart()) {
465     if (auto cplx = mlir::dyn_cast<mlir::ComplexType>(outputElementType))
466       outputElementType = cplx.getElementType();
467     else
468       return emitOpError("memref or component must have complex type if "
469                          "complex_part is provided");
470   }
471   mlir::Type resultBaseType =
472       getFortranElementOrSequenceType(getResult().getType());
473   unsigned resultRank = 0;
474   if (auto resultSeqType = mlir::dyn_cast<fir::SequenceType>(resultBaseType))
475     resultRank = resultSeqType.getDimension();
476   if (resultRank != outputRank)
477     return emitOpError("result type rank is not consistent with operands, "
478                        "expected rank ")
479            << outputRank;
480   mlir::Type resultElementType = fir::unwrapSequenceType(resultBaseType);
481   // result type must match the one that was inferred here, except the character
482   // length may differ because of substrings.
483   if (resultElementType != outputElementType &&
484       !(mlir::isa<fir::CharacterType>(resultElementType) &&
485         mlir::isa<fir::CharacterType>(outputElementType)))
486     return emitOpError(
487                "result element type is not consistent with operands, expected ")
488            << outputElementType;
489 
490   if (isBoxAddressType(getResult().getType())) {
491     if (!hasBoxComponent || numSubscripts != 0 || !getSubstring().empty() ||
492         getComplexPart())
493       return emitOpError(
494           "result type must only be a box address type if it designates a "
495           "component that is a fir.box or fir.class and if there are no "
496           "indices, substrings, and complex part");
497 
498   } else {
499     if ((resultRank == 0) != !getShape())
500       return emitOpError("shape must be provided if and only if the result is "
501                          "an array that is not a box address");
502     if (resultRank != 0) {
503       auto shapeType = mlir::dyn_cast<fir::ShapeType>(getShape().getType());
504       auto shapeShiftType =
505           mlir::dyn_cast<fir::ShapeShiftType>(getShape().getType());
506       if (!((shapeType && shapeType.getRank() == resultRank) ||
507             (shapeShiftType && shapeShiftType.getRank() == resultRank)))
508         return emitOpError("shape must be a fir.shape or fir.shapeshift with "
509                            "the rank of the result");
510     }
511     if (auto res =
512             verifyTypeparams(*this, outputElementType, getTypeparams().size());
513         failed(res))
514       return res;
515   }
516   return mlir::success();
517 }
518 
519 //===----------------------------------------------------------------------===//
520 // ParentComponentOp
521 //===----------------------------------------------------------------------===//
522 
523 llvm::LogicalResult hlfir::ParentComponentOp::verify() {
524   mlir::Type baseType =
525       hlfir::getFortranElementOrSequenceType(getMemref().getType());
526   auto maybeInputSeqType = mlir::dyn_cast<fir::SequenceType>(baseType);
527   unsigned inputTypeRank =
528       maybeInputSeqType ? maybeInputSeqType.getDimension() : 0;
529   unsigned shapeRank = 0;
530   if (mlir::Value shape = getShape())
531     if (auto shapeType = mlir::dyn_cast<fir::ShapeType>(shape.getType()))
532       shapeRank = shapeType.getRank();
533   if (inputTypeRank != shapeRank)
534     return emitOpError(
535         "must be provided a shape if and only if the base is an array");
536   mlir::Type outputBaseType = hlfir::getFortranElementOrSequenceType(getType());
537   auto maybeOutputSeqType = mlir::dyn_cast<fir::SequenceType>(outputBaseType);
538   unsigned outputTypeRank =
539       maybeOutputSeqType ? maybeOutputSeqType.getDimension() : 0;
540   if (inputTypeRank != outputTypeRank)
541     return emitOpError("result type rank must match input type rank");
542   if (maybeOutputSeqType && maybeInputSeqType)
543     for (auto [inputDim, outputDim] :
544          llvm::zip(maybeInputSeqType.getShape(), maybeOutputSeqType.getShape()))
545       if (inputDim != fir::SequenceType::getUnknownExtent() &&
546           outputDim != fir::SequenceType::getUnknownExtent())
547         if (inputDim != outputDim)
548           return emitOpError(
549               "result type extents are inconsistent with memref type");
550   fir::RecordType baseRecType =
551       mlir::dyn_cast<fir::RecordType>(hlfir::getFortranElementType(baseType));
552   fir::RecordType outRecType = mlir::dyn_cast<fir::RecordType>(
553       hlfir::getFortranElementType(outputBaseType));
554   if (!baseRecType || !outRecType)
555     return emitOpError("result type and input type must be derived types");
556 
557   // Note: result should not be a fir.class: its dynamic type is being set to
558   // the parent type and allowing fir.class would break the operation codegen:
559   // it would keep the input dynamic type.
560   if (mlir::isa<fir::ClassType>(getType()))
561     return emitOpError("result type must not be polymorphic");
562 
563   // The array results are known to not be dis-contiguous in most cases (the
564   // exception being if the parent type was extended by a type without any
565   // components): require a fir.box to be used for the result to carry the
566   // strides.
567   if (!mlir::isa<fir::BoxType>(getType()) &&
568       (outputTypeRank != 0 || fir::isRecordWithTypeParameters(outRecType)))
569     return emitOpError("result type must be a fir.box if the result is an "
570                        "array or has length parameters");
571   return mlir::success();
572 }
573 
574 //===----------------------------------------------------------------------===//
575 // LogicalReductionOp
576 //===----------------------------------------------------------------------===//
577 template <typename LogicalReductionOp>
578 static llvm::LogicalResult
579 verifyLogicalReductionOp(LogicalReductionOp reductionOp) {
580   mlir::Operation *op = reductionOp->getOperation();
581 
582   auto results = op->getResultTypes();
583   assert(results.size() == 1);
584 
585   mlir::Value mask = reductionOp->getMask();
586   mlir::Value dim = reductionOp->getDim();
587 
588   fir::SequenceType maskTy = mlir::cast<fir::SequenceType>(
589       hlfir::getFortranElementOrSequenceType(mask.getType()));
590   mlir::Type logicalTy = maskTy.getEleTy();
591   llvm::ArrayRef<int64_t> maskShape = maskTy.getShape();
592 
593   mlir::Type resultType = results[0];
594   if (mlir::isa<fir::LogicalType>(resultType)) {
595     // Result is of the same type as MASK
596     if ((resultType != logicalTy) && useStrictIntrinsicVerifier)
597       return reductionOp->emitOpError(
598           "result must have the same element type as MASK argument");
599 
600   } else if (auto resultExpr =
601                  mlir::dyn_cast_or_null<hlfir::ExprType>(resultType)) {
602     // Result should only be in hlfir.expr form if it is an array
603     if (maskShape.size() > 1 && dim != nullptr) {
604       if (!resultExpr.isArray())
605         return reductionOp->emitOpError("result must be an array");
606 
607       if ((resultExpr.getEleTy() != logicalTy) && useStrictIntrinsicVerifier)
608         return reductionOp->emitOpError(
609             "result must have the same element type as MASK argument");
610 
611       llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
612       // Result has rank n-1
613       if (resultShape.size() != (maskShape.size() - 1))
614         return reductionOp->emitOpError(
615             "result rank must be one less than MASK");
616     } else {
617       return reductionOp->emitOpError("result must be of logical type");
618     }
619   } else {
620     return reductionOp->emitOpError("result must be of logical type");
621   }
622   return mlir::success();
623 }
624 
625 //===----------------------------------------------------------------------===//
626 // AllOp
627 //===----------------------------------------------------------------------===//
628 
629 llvm::LogicalResult hlfir::AllOp::verify() {
630   return verifyLogicalReductionOp<hlfir::AllOp *>(this);
631 }
632 
633 void hlfir::AllOp::getEffects(
634     llvm::SmallVectorImpl<
635         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
636         &effects) {
637   getIntrinsicEffects(getOperation(), effects);
638 }
639 
640 //===----------------------------------------------------------------------===//
641 // AnyOp
642 //===----------------------------------------------------------------------===//
643 
644 llvm::LogicalResult hlfir::AnyOp::verify() {
645   return verifyLogicalReductionOp<hlfir::AnyOp *>(this);
646 }
647 
648 void hlfir::AnyOp::getEffects(
649     llvm::SmallVectorImpl<
650         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
651         &effects) {
652   getIntrinsicEffects(getOperation(), effects);
653 }
654 
655 //===----------------------------------------------------------------------===//
656 // CountOp
657 //===----------------------------------------------------------------------===//
658 
659 llvm::LogicalResult hlfir::CountOp::verify() {
660   mlir::Operation *op = getOperation();
661 
662   auto results = op->getResultTypes();
663   assert(results.size() == 1);
664   mlir::Value mask = getMask();
665   mlir::Value dim = getDim();
666 
667   fir::SequenceType maskTy = mlir::cast<fir::SequenceType>(
668       hlfir::getFortranElementOrSequenceType(mask.getType()));
669   llvm::ArrayRef<int64_t> maskShape = maskTy.getShape();
670 
671   mlir::Type resultType = results[0];
672   if (auto resultExpr = mlir::dyn_cast_or_null<hlfir::ExprType>(resultType)) {
673     if (maskShape.size() > 1 && dim != nullptr) {
674       if (!resultExpr.isArray())
675         return emitOpError("result must be an array");
676 
677       llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
678       // Result has rank n-1
679       if (resultShape.size() != (maskShape.size() - 1))
680         return emitOpError("result rank must be one less than MASK");
681     } else {
682       return emitOpError("result must be of numerical array type");
683     }
684   } else if (!hlfir::isFortranScalarNumericalType(resultType)) {
685     return emitOpError("result must be of numerical scalar type");
686   }
687 
688   return mlir::success();
689 }
690 
691 void hlfir::CountOp::getEffects(
692     llvm::SmallVectorImpl<
693         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
694         &effects) {
695   getIntrinsicEffects(getOperation(), effects);
696 }
697 
698 //===----------------------------------------------------------------------===//
699 // ConcatOp
700 //===----------------------------------------------------------------------===//
701 
702 static unsigned getCharacterKind(mlir::Type t) {
703   return mlir::cast<fir::CharacterType>(hlfir::getFortranElementType(t))
704       .getFKind();
705 }
706 
707 static std::optional<fir::CharacterType::LenType>
708 getCharacterLengthIfStatic(mlir::Type t) {
709   if (auto charType =
710           mlir::dyn_cast<fir::CharacterType>(hlfir::getFortranElementType(t)))
711     if (charType.hasConstantLen())
712       return charType.getLen();
713   return std::nullopt;
714 }
715 
716 llvm::LogicalResult hlfir::ConcatOp::verify() {
717   if (getStrings().size() < 2)
718     return emitOpError("must be provided at least two string operands");
719   unsigned kind = getCharacterKind(getResult().getType());
720   for (auto string : getStrings())
721     if (kind != getCharacterKind(string.getType()))
722       return emitOpError("strings must have the same KIND as the result type");
723   return mlir::success();
724 }
725 
726 void hlfir::ConcatOp::build(mlir::OpBuilder &builder,
727                             mlir::OperationState &result,
728                             mlir::ValueRange strings, mlir::Value len) {
729   fir::CharacterType::LenType resultTypeLen = 0;
730   assert(!strings.empty() && "must contain operands");
731   unsigned kind = getCharacterKind(strings[0].getType());
732   for (auto string : strings)
733     if (auto cstLen = getCharacterLengthIfStatic(string.getType())) {
734       resultTypeLen += *cstLen;
735     } else {
736       resultTypeLen = fir::CharacterType::unknownLen();
737       break;
738     }
739   auto resultType = hlfir::ExprType::get(
740       builder.getContext(), hlfir::ExprType::Shape{},
741       fir::CharacterType::get(builder.getContext(), kind, resultTypeLen),
742       false);
743   build(builder, result, resultType, strings, len);
744 }
745 
746 void hlfir::ConcatOp::getEffects(
747     llvm::SmallVectorImpl<
748         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
749         &effects) {
750   getIntrinsicEffects(getOperation(), effects);
751 }
752 
753 //===----------------------------------------------------------------------===//
754 // NumericalReductionOp
755 //===----------------------------------------------------------------------===//
756 
757 template <typename NumericalReductionOp>
758 static llvm::LogicalResult
759 verifyArrayAndMaskForReductionOp(NumericalReductionOp reductionOp) {
760   mlir::Value array = reductionOp->getArray();
761   mlir::Value mask = reductionOp->getMask();
762 
763   fir::SequenceType arrayTy = mlir::cast<fir::SequenceType>(
764       hlfir::getFortranElementOrSequenceType(array.getType()));
765   llvm::ArrayRef<int64_t> arrayShape = arrayTy.getShape();
766 
767   if (mask) {
768     fir::SequenceType maskSeq = mlir::dyn_cast<fir::SequenceType>(
769         hlfir::getFortranElementOrSequenceType(mask.getType()));
770     llvm::ArrayRef<int64_t> maskShape;
771 
772     if (maskSeq)
773       maskShape = maskSeq.getShape();
774 
775     if (!maskShape.empty()) {
776       if (maskShape.size() != arrayShape.size())
777         return reductionOp->emitWarning("MASK must be conformable to ARRAY");
778       if (useStrictIntrinsicVerifier) {
779         static_assert(fir::SequenceType::getUnknownExtent() ==
780                       hlfir::ExprType::getUnknownExtent());
781         constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent();
782         for (std::size_t i = 0; i < arrayShape.size(); ++i) {
783           int64_t arrayExtent = arrayShape[i];
784           int64_t maskExtent = maskShape[i];
785           if ((arrayExtent != maskExtent) && (arrayExtent != unknownExtent) &&
786               (maskExtent != unknownExtent))
787             return reductionOp->emitWarning(
788                 "MASK must be conformable to ARRAY");
789         }
790       }
791     }
792   }
793   return mlir::success();
794 }
795 
796 template <typename NumericalReductionOp>
797 static llvm::LogicalResult
798 verifyNumericalReductionOp(NumericalReductionOp reductionOp) {
799   mlir::Operation *op = reductionOp->getOperation();
800   auto results = op->getResultTypes();
801   assert(results.size() == 1);
802 
803   auto res = verifyArrayAndMaskForReductionOp(reductionOp);
804   if (failed(res))
805     return res;
806 
807   mlir::Value array = reductionOp->getArray();
808   mlir::Value dim = reductionOp->getDim();
809   fir::SequenceType arrayTy = mlir::cast<fir::SequenceType>(
810       hlfir::getFortranElementOrSequenceType(array.getType()));
811   mlir::Type numTy = arrayTy.getEleTy();
812   llvm::ArrayRef<int64_t> arrayShape = arrayTy.getShape();
813 
814   mlir::Type resultType = results[0];
815   if (hlfir::isFortranScalarNumericalType(resultType)) {
816     // Result is of the same type as ARRAY
817     if ((resultType != numTy) && useStrictIntrinsicVerifier)
818       return reductionOp->emitOpError(
819           "result must have the same element type as ARRAY argument");
820 
821   } else if (auto resultExpr =
822                  mlir::dyn_cast_or_null<hlfir::ExprType>(resultType)) {
823     if (arrayShape.size() > 1 && dim != nullptr) {
824       if (!resultExpr.isArray())
825         return reductionOp->emitOpError("result must be an array");
826 
827       if ((resultExpr.getEleTy() != numTy) && useStrictIntrinsicVerifier)
828         return reductionOp->emitOpError(
829             "result must have the same element type as ARRAY argument");
830 
831       llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
832       // Result has rank n-1
833       if (resultShape.size() != (arrayShape.size() - 1))
834         return reductionOp->emitOpError(
835             "result rank must be one less than ARRAY");
836     } else {
837       return reductionOp->emitOpError(
838           "result must be of numerical scalar type");
839     }
840   } else {
841     return reductionOp->emitOpError("result must be of numerical scalar type");
842   }
843   return mlir::success();
844 }
845 
846 //===----------------------------------------------------------------------===//
847 // ProductOp
848 //===----------------------------------------------------------------------===//
849 
850 llvm::LogicalResult hlfir::ProductOp::verify() {
851   return verifyNumericalReductionOp<hlfir::ProductOp *>(this);
852 }
853 
854 void hlfir::ProductOp::getEffects(
855     llvm::SmallVectorImpl<
856         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
857         &effects) {
858   getIntrinsicEffects(getOperation(), effects);
859 }
860 
861 //===----------------------------------------------------------------------===//
862 // CharacterReductionOp
863 //===----------------------------------------------------------------------===//
864 
865 template <typename CharacterReductionOp>
866 static llvm::LogicalResult
867 verifyCharacterReductionOp(CharacterReductionOp reductionOp) {
868   mlir::Operation *op = reductionOp->getOperation();
869   auto results = op->getResultTypes();
870   assert(results.size() == 1);
871 
872   auto res = verifyArrayAndMaskForReductionOp(reductionOp);
873   if (failed(res))
874     return res;
875 
876   mlir::Value array = reductionOp->getArray();
877   mlir::Value dim = reductionOp->getDim();
878   fir::SequenceType arrayTy = mlir::cast<fir::SequenceType>(
879       hlfir::getFortranElementOrSequenceType(array.getType()));
880   mlir::Type numTy = arrayTy.getEleTy();
881   llvm::ArrayRef<int64_t> arrayShape = arrayTy.getShape();
882 
883   auto resultExpr = mlir::cast<hlfir::ExprType>(results[0]);
884   mlir::Type resultType = resultExpr.getEleTy();
885   assert(mlir::isa<fir::CharacterType>(resultType) &&
886          "result must be character");
887 
888   // Result is of the same type as ARRAY
889   if ((resultType != numTy) && useStrictIntrinsicVerifier)
890     return reductionOp->emitOpError(
891         "result must have the same element type as ARRAY argument");
892 
893   if (arrayShape.size() > 1 && dim != nullptr) {
894     if (!resultExpr.isArray())
895       return reductionOp->emitOpError("result must be an array");
896     llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
897     // Result has rank n-1
898     if (resultShape.size() != (arrayShape.size() - 1))
899       return reductionOp->emitOpError(
900           "result rank must be one less than ARRAY");
901   } else if (!resultExpr.isScalar()) {
902     return reductionOp->emitOpError("result must be scalar character");
903   }
904   return mlir::success();
905 }
906 
907 //===----------------------------------------------------------------------===//
908 // MaxvalOp
909 //===----------------------------------------------------------------------===//
910 
911 llvm::LogicalResult hlfir::MaxvalOp::verify() {
912   mlir::Operation *op = getOperation();
913 
914   auto results = op->getResultTypes();
915   assert(results.size() == 1);
916 
917   auto resultExpr = mlir::dyn_cast<hlfir::ExprType>(results[0]);
918   if (resultExpr && mlir::isa<fir::CharacterType>(resultExpr.getEleTy())) {
919     return verifyCharacterReductionOp<hlfir::MaxvalOp *>(this);
920   }
921   return verifyNumericalReductionOp<hlfir::MaxvalOp *>(this);
922 }
923 
924 void hlfir::MaxvalOp::getEffects(
925     llvm::SmallVectorImpl<
926         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
927         &effects) {
928   getIntrinsicEffects(getOperation(), effects);
929 }
930 
931 //===----------------------------------------------------------------------===//
932 // MinvalOp
933 //===----------------------------------------------------------------------===//
934 
935 llvm::LogicalResult hlfir::MinvalOp::verify() {
936   mlir::Operation *op = getOperation();
937 
938   auto results = op->getResultTypes();
939   assert(results.size() == 1);
940 
941   auto resultExpr = mlir::dyn_cast<hlfir::ExprType>(results[0]);
942   if (resultExpr && mlir::isa<fir::CharacterType>(resultExpr.getEleTy())) {
943     return verifyCharacterReductionOp<hlfir::MinvalOp *>(this);
944   }
945   return verifyNumericalReductionOp<hlfir::MinvalOp *>(this);
946 }
947 
948 void hlfir::MinvalOp::getEffects(
949     llvm::SmallVectorImpl<
950         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
951         &effects) {
952   getIntrinsicEffects(getOperation(), effects);
953 }
954 
955 //===----------------------------------------------------------------------===//
956 // MinlocOp
957 //===----------------------------------------------------------------------===//
958 
959 template <typename NumericalReductionOp>
960 static llvm::LogicalResult
961 verifyResultForMinMaxLoc(NumericalReductionOp reductionOp) {
962   mlir::Operation *op = reductionOp->getOperation();
963   auto results = op->getResultTypes();
964   assert(results.size() == 1);
965 
966   mlir::Value array = reductionOp->getArray();
967   mlir::Value dim = reductionOp->getDim();
968   fir::SequenceType arrayTy = mlir::cast<fir::SequenceType>(
969       hlfir::getFortranElementOrSequenceType(array.getType()));
970   llvm::ArrayRef<int64_t> arrayShape = arrayTy.getShape();
971 
972   mlir::Type resultType = results[0];
973   if (dim && arrayShape.size() == 1) {
974     if (!fir::isa_integer(resultType))
975       return reductionOp->emitOpError("result must be scalar integer");
976   } else if (auto resultExpr =
977                  mlir::dyn_cast_or_null<hlfir::ExprType>(resultType)) {
978     if (!resultExpr.isArray())
979       return reductionOp->emitOpError("result must be an array");
980 
981     if (!fir::isa_integer(resultExpr.getEleTy()))
982       return reductionOp->emitOpError("result must have integer elements");
983 
984     llvm::ArrayRef<int64_t> resultShape = resultExpr.getShape();
985     // With dim the result has rank n-1
986     if (dim && resultShape.size() != (arrayShape.size() - 1))
987       return reductionOp->emitOpError(
988           "result rank must be one less than ARRAY");
989     // With dim the result has rank n
990     if (!dim && resultShape.size() != 1)
991       return reductionOp->emitOpError("result rank must be 1");
992   } else {
993     return reductionOp->emitOpError("result must be of numerical expr type");
994   }
995   return mlir::success();
996 }
997 
998 llvm::LogicalResult hlfir::MinlocOp::verify() {
999   auto res = verifyArrayAndMaskForReductionOp(this);
1000   if (failed(res))
1001     return res;
1002 
1003   return verifyResultForMinMaxLoc(this);
1004 }
1005 
1006 void hlfir::MinlocOp::getEffects(
1007     llvm::SmallVectorImpl<
1008         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1009         &effects) {
1010   getIntrinsicEffects(getOperation(), effects);
1011 }
1012 
1013 //===----------------------------------------------------------------------===//
1014 // MaxlocOp
1015 //===----------------------------------------------------------------------===//
1016 
1017 llvm::LogicalResult hlfir::MaxlocOp::verify() {
1018   auto res = verifyArrayAndMaskForReductionOp(this);
1019   if (failed(res))
1020     return res;
1021 
1022   return verifyResultForMinMaxLoc(this);
1023 }
1024 
1025 void hlfir::MaxlocOp::getEffects(
1026     llvm::SmallVectorImpl<
1027         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1028         &effects) {
1029   getIntrinsicEffects(getOperation(), effects);
1030 }
1031 
1032 //===----------------------------------------------------------------------===//
1033 // SetLengthOp
1034 //===----------------------------------------------------------------------===//
1035 
1036 void hlfir::SetLengthOp::build(mlir::OpBuilder &builder,
1037                                mlir::OperationState &result, mlir::Value string,
1038                                mlir::Value len) {
1039   fir::CharacterType::LenType resultTypeLen = fir::CharacterType::unknownLen();
1040   if (auto cstLen = fir::getIntIfConstant(len))
1041     resultTypeLen = *cstLen;
1042   unsigned kind = getCharacterKind(string.getType());
1043   auto resultType = hlfir::ExprType::get(
1044       builder.getContext(), hlfir::ExprType::Shape{},
1045       fir::CharacterType::get(builder.getContext(), kind, resultTypeLen),
1046       false);
1047   build(builder, result, resultType, string, len);
1048 }
1049 
1050 void hlfir::SetLengthOp::getEffects(
1051     llvm::SmallVectorImpl<
1052         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1053         &effects) {
1054   getIntrinsicEffects(getOperation(), effects);
1055 }
1056 
1057 //===----------------------------------------------------------------------===//
1058 // SumOp
1059 //===----------------------------------------------------------------------===//
1060 
1061 llvm::LogicalResult hlfir::SumOp::verify() {
1062   return verifyNumericalReductionOp<hlfir::SumOp *>(this);
1063 }
1064 
1065 void hlfir::SumOp::getEffects(
1066     llvm::SmallVectorImpl<
1067         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1068         &effects) {
1069   getIntrinsicEffects(getOperation(), effects);
1070 }
1071 
1072 //===----------------------------------------------------------------------===//
1073 // DotProductOp
1074 //===----------------------------------------------------------------------===//
1075 
1076 llvm::LogicalResult hlfir::DotProductOp::verify() {
1077   mlir::Value lhs = getLhs();
1078   mlir::Value rhs = getRhs();
1079   fir::SequenceType lhsTy = mlir::cast<fir::SequenceType>(
1080       hlfir::getFortranElementOrSequenceType(lhs.getType()));
1081   fir::SequenceType rhsTy = mlir::cast<fir::SequenceType>(
1082       hlfir::getFortranElementOrSequenceType(rhs.getType()));
1083   llvm::ArrayRef<int64_t> lhsShape = lhsTy.getShape();
1084   llvm::ArrayRef<int64_t> rhsShape = rhsTy.getShape();
1085   std::size_t lhsRank = lhsShape.size();
1086   std::size_t rhsRank = rhsShape.size();
1087   mlir::Type lhsEleTy = lhsTy.getEleTy();
1088   mlir::Type rhsEleTy = rhsTy.getEleTy();
1089   mlir::Type resultTy = getResult().getType();
1090 
1091   if ((lhsRank != 1) || (rhsRank != 1))
1092     return emitOpError("both arrays must have rank 1");
1093 
1094   int64_t lhsSize = lhsShape[0];
1095   int64_t rhsSize = rhsShape[0];
1096 
1097   constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent();
1098   if ((lhsSize != unknownExtent) && (rhsSize != unknownExtent) &&
1099       (lhsSize != rhsSize) && useStrictIntrinsicVerifier)
1100     return emitOpError("both arrays must have the same size");
1101 
1102   if (useStrictIntrinsicVerifier) {
1103     if (mlir::isa<fir::LogicalType>(lhsEleTy) !=
1104         mlir::isa<fir::LogicalType>(rhsEleTy))
1105       return emitOpError("if one array is logical, so should the other be");
1106 
1107     if (mlir::isa<fir::LogicalType>(lhsEleTy) !=
1108         mlir::isa<fir::LogicalType>(resultTy))
1109       return emitOpError("the result type should be a logical only if the "
1110                          "argument types are logical");
1111   }
1112 
1113   if (!hlfir::isFortranScalarNumericalType(resultTy) &&
1114       !mlir::isa<fir::LogicalType>(resultTy))
1115     return emitOpError(
1116         "the result must be of scalar numerical or logical type");
1117 
1118   return mlir::success();
1119 }
1120 
1121 void hlfir::DotProductOp::getEffects(
1122     llvm::SmallVectorImpl<
1123         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1124         &effects) {
1125   getIntrinsicEffects(getOperation(), effects);
1126 }
1127 
1128 //===----------------------------------------------------------------------===//
1129 // MatmulOp
1130 //===----------------------------------------------------------------------===//
1131 
1132 llvm::LogicalResult hlfir::MatmulOp::verify() {
1133   mlir::Value lhs = getLhs();
1134   mlir::Value rhs = getRhs();
1135   fir::SequenceType lhsTy = mlir::cast<fir::SequenceType>(
1136       hlfir::getFortranElementOrSequenceType(lhs.getType()));
1137   fir::SequenceType rhsTy = mlir::cast<fir::SequenceType>(
1138       hlfir::getFortranElementOrSequenceType(rhs.getType()));
1139   llvm::ArrayRef<int64_t> lhsShape = lhsTy.getShape();
1140   llvm::ArrayRef<int64_t> rhsShape = rhsTy.getShape();
1141   std::size_t lhsRank = lhsShape.size();
1142   std::size_t rhsRank = rhsShape.size();
1143   mlir::Type lhsEleTy = lhsTy.getEleTy();
1144   mlir::Type rhsEleTy = rhsTy.getEleTy();
1145   hlfir::ExprType resultTy = mlir::cast<hlfir::ExprType>(getResult().getType());
1146   llvm::ArrayRef<int64_t> resultShape = resultTy.getShape();
1147   mlir::Type resultEleTy = resultTy.getEleTy();
1148 
1149   if (((lhsRank != 1) && (lhsRank != 2)) || ((rhsRank != 1) && (rhsRank != 2)))
1150     return emitOpError("array must have either rank 1 or rank 2");
1151 
1152   if ((lhsRank == 1) && (rhsRank == 1))
1153     return emitOpError("at least one array must have rank 2");
1154 
1155   if (mlir::isa<fir::LogicalType>(lhsEleTy) !=
1156       mlir::isa<fir::LogicalType>(rhsEleTy))
1157     return emitOpError("if one array is logical, so should the other be");
1158 
1159   if (!useStrictIntrinsicVerifier)
1160     return mlir::success();
1161 
1162   int64_t lastLhsDim = lhsShape[lhsRank - 1];
1163   int64_t firstRhsDim = rhsShape[0];
1164   constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent();
1165   if (lastLhsDim != firstRhsDim)
1166     if ((lastLhsDim != unknownExtent) && (firstRhsDim != unknownExtent))
1167       return emitOpError(
1168           "the last dimension of LHS should match the first dimension of RHS");
1169 
1170   if (mlir::isa<fir::LogicalType>(lhsEleTy) !=
1171       mlir::isa<fir::LogicalType>(resultEleTy))
1172     return emitOpError("the result type should be a logical only if the "
1173                        "argument types are logical");
1174 
1175   llvm::SmallVector<int64_t, 2> expectedResultShape;
1176   if (lhsRank == 2) {
1177     if (rhsRank == 2) {
1178       expectedResultShape.push_back(lhsShape[0]);
1179       expectedResultShape.push_back(rhsShape[1]);
1180     } else {
1181       // rhsRank == 1
1182       expectedResultShape.push_back(lhsShape[0]);
1183     }
1184   } else {
1185     // lhsRank == 1
1186     // rhsRank == 2
1187     expectedResultShape.push_back(rhsShape[1]);
1188   }
1189   if (resultShape.size() != expectedResultShape.size())
1190     return emitOpError("incorrect result shape");
1191   if (resultShape[0] != expectedResultShape[0] &&
1192       expectedResultShape[0] != unknownExtent)
1193     return emitOpError("incorrect result shape");
1194   if (resultShape.size() == 2 && resultShape[1] != expectedResultShape[1] &&
1195       expectedResultShape[1] != unknownExtent)
1196     return emitOpError("incorrect result shape");
1197 
1198   return mlir::success();
1199 }
1200 
1201 llvm::LogicalResult
1202 hlfir::MatmulOp::canonicalize(MatmulOp matmulOp,
1203                               mlir::PatternRewriter &rewriter) {
1204   // the only two uses of the transposed matrix should be for the hlfir.matmul
1205   // and hlfir.destroy
1206   auto isOtherwiseUnused = [&](hlfir::TransposeOp transposeOp) -> bool {
1207     std::size_t numUses = 0;
1208     for (mlir::Operation *user : transposeOp.getResult().getUsers()) {
1209       ++numUses;
1210       if (user == matmulOp)
1211         continue;
1212       if (mlir::dyn_cast_or_null<hlfir::DestroyOp>(user))
1213         continue;
1214       // some other use!
1215       return false;
1216     }
1217     return numUses <= 2;
1218   };
1219 
1220   mlir::Value lhs = matmulOp.getLhs();
1221   // Rewrite MATMUL(TRANSPOSE(lhs), rhs) => hlfir.matmul_transpose lhs, rhs
1222   if (auto transposeOp = lhs.getDefiningOp<hlfir::TransposeOp>()) {
1223     if (isOtherwiseUnused(transposeOp)) {
1224       mlir::Location loc = matmulOp.getLoc();
1225       mlir::Type resultTy = matmulOp.getResult().getType();
1226       auto matmulTransposeOp = rewriter.create<hlfir::MatmulTransposeOp>(
1227           loc, resultTy, transposeOp.getArray(), matmulOp.getRhs(),
1228           matmulOp.getFastmathAttr());
1229 
1230       // we don't need to remove any hlfir.destroy because it will be needed for
1231       // the new intrinsic result anyway
1232       rewriter.replaceOp(matmulOp, matmulTransposeOp.getResult());
1233 
1234       // but we do need to get rid of the hlfir.destroy for the hlfir.transpose
1235       // result (which is entirely removed)
1236       llvm::SmallVector<mlir::Operation *> users(
1237           transposeOp->getResult(0).getUsers());
1238       for (mlir::Operation *user : users)
1239         if (auto destroyOp = mlir::dyn_cast_or_null<hlfir::DestroyOp>(user))
1240           rewriter.eraseOp(destroyOp);
1241       rewriter.eraseOp(transposeOp);
1242 
1243       return mlir::success();
1244     }
1245   }
1246 
1247   return mlir::failure();
1248 }
1249 
1250 void hlfir::MatmulOp::getEffects(
1251     llvm::SmallVectorImpl<
1252         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1253         &effects) {
1254   getIntrinsicEffects(getOperation(), effects);
1255 }
1256 
1257 //===----------------------------------------------------------------------===//
1258 // TransposeOp
1259 //===----------------------------------------------------------------------===//
1260 
1261 llvm::LogicalResult hlfir::TransposeOp::verify() {
1262   mlir::Value array = getArray();
1263   fir::SequenceType arrayTy = mlir::cast<fir::SequenceType>(
1264       hlfir::getFortranElementOrSequenceType(array.getType()));
1265   llvm::ArrayRef<int64_t> inShape = arrayTy.getShape();
1266   std::size_t rank = inShape.size();
1267   mlir::Type eleTy = arrayTy.getEleTy();
1268   hlfir::ExprType resultTy = mlir::cast<hlfir::ExprType>(getResult().getType());
1269   llvm::ArrayRef<int64_t> resultShape = resultTy.getShape();
1270   std::size_t resultRank = resultShape.size();
1271   mlir::Type resultEleTy = resultTy.getEleTy();
1272 
1273   if (rank != 2 || resultRank != 2)
1274     return emitOpError("input and output arrays should have rank 2");
1275 
1276   if (!useStrictIntrinsicVerifier)
1277     return mlir::success();
1278 
1279   constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent();
1280   if ((inShape[0] != resultShape[1]) && (inShape[0] != unknownExtent))
1281     return emitOpError("output shape does not match input array");
1282   if ((inShape[1] != resultShape[0]) && (inShape[1] != unknownExtent))
1283     return emitOpError("output shape does not match input array");
1284 
1285   if (eleTy != resultEleTy)
1286     return emitOpError(
1287         "input and output arrays should have the same element type");
1288 
1289   return mlir::success();
1290 }
1291 
1292 void hlfir::TransposeOp::getEffects(
1293     llvm::SmallVectorImpl<
1294         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1295         &effects) {
1296   getIntrinsicEffects(getOperation(), effects);
1297 }
1298 
1299 //===----------------------------------------------------------------------===//
1300 // MatmulTransposeOp
1301 //===----------------------------------------------------------------------===//
1302 
1303 llvm::LogicalResult hlfir::MatmulTransposeOp::verify() {
1304   mlir::Value lhs = getLhs();
1305   mlir::Value rhs = getRhs();
1306   fir::SequenceType lhsTy = mlir::cast<fir::SequenceType>(
1307       hlfir::getFortranElementOrSequenceType(lhs.getType()));
1308   fir::SequenceType rhsTy = mlir::cast<fir::SequenceType>(
1309       hlfir::getFortranElementOrSequenceType(rhs.getType()));
1310   llvm::ArrayRef<int64_t> lhsShape = lhsTy.getShape();
1311   llvm::ArrayRef<int64_t> rhsShape = rhsTy.getShape();
1312   std::size_t lhsRank = lhsShape.size();
1313   std::size_t rhsRank = rhsShape.size();
1314   mlir::Type lhsEleTy = lhsTy.getEleTy();
1315   mlir::Type rhsEleTy = rhsTy.getEleTy();
1316   hlfir::ExprType resultTy = mlir::cast<hlfir::ExprType>(getResult().getType());
1317   llvm::ArrayRef<int64_t> resultShape = resultTy.getShape();
1318   mlir::Type resultEleTy = resultTy.getEleTy();
1319 
1320   // lhs must have rank 2 for the transpose to be valid
1321   if ((lhsRank != 2) || ((rhsRank != 1) && (rhsRank != 2)))
1322     return emitOpError("array must have either rank 1 or rank 2");
1323 
1324   if (!useStrictIntrinsicVerifier)
1325     return mlir::success();
1326 
1327   if (mlir::isa<fir::LogicalType>(lhsEleTy) !=
1328       mlir::isa<fir::LogicalType>(rhsEleTy))
1329     return emitOpError("if one array is logical, so should the other be");
1330 
1331   // for matmul we compare the last dimension of lhs with the first dimension of
1332   // rhs, but for MatmulTranspose, dimensions of lhs are inverted by the
1333   // transpose
1334   int64_t firstLhsDim = lhsShape[0];
1335   int64_t firstRhsDim = rhsShape[0];
1336   constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent();
1337   if (firstLhsDim != firstRhsDim)
1338     if ((firstLhsDim != unknownExtent) && (firstRhsDim != unknownExtent))
1339       return emitOpError(
1340           "the first dimension of LHS should match the first dimension of RHS");
1341 
1342   if (mlir::isa<fir::LogicalType>(lhsEleTy) !=
1343       mlir::isa<fir::LogicalType>(resultEleTy))
1344     return emitOpError("the result type should be a logical only if the "
1345                        "argument types are logical");
1346 
1347   llvm::SmallVector<int64_t, 2> expectedResultShape;
1348   if (rhsRank == 2) {
1349     expectedResultShape.push_back(lhsShape[1]);
1350     expectedResultShape.push_back(rhsShape[1]);
1351   } else {
1352     // rhsRank == 1
1353     expectedResultShape.push_back(lhsShape[1]);
1354   }
1355   if (resultShape.size() != expectedResultShape.size())
1356     return emitOpError("incorrect result shape");
1357   if (resultShape[0] != expectedResultShape[0])
1358     return emitOpError("incorrect result shape");
1359   if (resultShape.size() == 2 && resultShape[1] != expectedResultShape[1])
1360     return emitOpError("incorrect result shape");
1361 
1362   return mlir::success();
1363 }
1364 
1365 void hlfir::MatmulTransposeOp::getEffects(
1366     llvm::SmallVectorImpl<
1367         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1368         &effects) {
1369   getIntrinsicEffects(getOperation(), effects);
1370 }
1371 
1372 //===----------------------------------------------------------------------===//
1373 // CShiftOp
1374 //===----------------------------------------------------------------------===//
1375 
1376 llvm::LogicalResult hlfir::CShiftOp::verify() {
1377   mlir::Value array = getArray();
1378   fir::SequenceType arrayTy = mlir::cast<fir::SequenceType>(
1379       hlfir::getFortranElementOrSequenceType(array.getType()));
1380   llvm::ArrayRef<int64_t> inShape = arrayTy.getShape();
1381   std::size_t arrayRank = inShape.size();
1382   mlir::Type eleTy = arrayTy.getEleTy();
1383   hlfir::ExprType resultTy = mlir::cast<hlfir::ExprType>(getResult().getType());
1384   llvm::ArrayRef<int64_t> resultShape = resultTy.getShape();
1385   std::size_t resultRank = resultShape.size();
1386   mlir::Type resultEleTy = resultTy.getEleTy();
1387   mlir::Value shift = getShift();
1388   mlir::Type shiftTy = hlfir::getFortranElementOrSequenceType(shift.getType());
1389 
1390   // TODO: turn allowCharacterLenMismatch into true.
1391   if (auto match = areMatchingTypes(*this, eleTy, resultEleTy,
1392                                     /*allowCharacterLenMismatch=*/false);
1393       match.failed())
1394     return emitOpError(
1395         "input and output arrays should have the same element type");
1396 
1397   if (arrayRank != resultRank)
1398     return emitOpError("input and output arrays should have the same rank");
1399 
1400   constexpr int64_t unknownExtent = fir::SequenceType::getUnknownExtent();
1401   for (auto [inDim, resultDim] : llvm::zip(inShape, resultShape))
1402     if (inDim != unknownExtent && resultDim != unknownExtent &&
1403         inDim != resultDim)
1404       return emitOpError(
1405           "output array's shape conflicts with the input array's shape");
1406 
1407   int64_t dimVal = -1;
1408   if (!getDim())
1409     dimVal = 1;
1410   else if (auto dim = fir::getIntIfConstant(getDim()))
1411     dimVal = *dim;
1412 
1413   // The DIM argument may be statically invalid (e.g. exceed the
1414   // input array rank) in dead code after constant propagation,
1415   // so avoid some checks unless useStrictIntrinsicVerifier is true.
1416   if (useStrictIntrinsicVerifier && dimVal != -1) {
1417     if (dimVal < 1)
1418       return emitOpError("DIM must be >= 1");
1419     if (dimVal > static_cast<int64_t>(arrayRank))
1420       return emitOpError("DIM must be <= input array's rank");
1421   }
1422 
1423   if (auto shiftSeqTy = mlir::dyn_cast<fir::SequenceType>(shiftTy)) {
1424     // SHIFT is an array. Verify the rank and the shape (if DIM is constant).
1425     llvm::ArrayRef<int64_t> shiftShape = shiftSeqTy.getShape();
1426     std::size_t shiftRank = shiftShape.size();
1427     if (shiftRank != arrayRank - 1)
1428       return emitOpError(
1429           "SHIFT's rank must be 1 less than the input array's rank");
1430 
1431     if (useStrictIntrinsicVerifier && dimVal != -1) {
1432       // SHIFT's shape must be [d(1), d(2), ..., d(DIM-1), d(DIM+1), ..., d(n)],
1433       // where [d(1), d(2), ..., d(n)] is the shape of the ARRAY.
1434       int64_t arrayDimIdx = 0;
1435       int64_t shiftDimIdx = 0;
1436       for (auto shiftDim : shiftShape) {
1437         if (arrayDimIdx == dimVal - 1)
1438           ++arrayDimIdx;
1439 
1440         if (inShape[arrayDimIdx] != unknownExtent &&
1441             shiftDim != unknownExtent && inShape[arrayDimIdx] != shiftDim)
1442           return emitOpError("SHAPE(ARRAY)(" + llvm::Twine(arrayDimIdx + 1) +
1443                              ") must be equal to SHAPE(SHIFT)(" +
1444                              llvm::Twine(shiftDimIdx + 1) +
1445                              "): " + llvm::Twine(inShape[arrayDimIdx]) +
1446                              " != " + llvm::Twine(shiftDim));
1447         ++arrayDimIdx;
1448         ++shiftDimIdx;
1449       }
1450     }
1451   }
1452 
1453   return mlir::success();
1454 }
1455 
1456 void hlfir::CShiftOp::getEffects(
1457     llvm::SmallVectorImpl<
1458         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1459         &effects) {
1460   getIntrinsicEffects(getOperation(), effects);
1461 }
1462 
1463 //===----------------------------------------------------------------------===//
1464 // ReshapeOp
1465 //===----------------------------------------------------------------------===//
1466 
1467 llvm::LogicalResult hlfir::ReshapeOp::verify() {
1468   auto results = getOperation()->getResultTypes();
1469   assert(results.size() == 1);
1470   hlfir::ExprType resultType = mlir::cast<hlfir::ExprType>(results[0]);
1471   mlir::Value array = getArray();
1472   auto arrayType = mlir::cast<fir::SequenceType>(
1473       hlfir::getFortranElementOrSequenceType(array.getType()));
1474   if (auto match = areMatchingTypes(
1475           *this, hlfir::getFortranElementType(resultType),
1476           arrayType.getElementType(), /*allowCharacterLenMismatch=*/true);
1477       match.failed())
1478     return emitOpError("ARRAY and the result must have the same element type");
1479   if (hlfir::isPolymorphicType(resultType) !=
1480       hlfir::isPolymorphicType(array.getType()))
1481     return emitOpError("ARRAY must be polymorphic iff result is polymorphic");
1482 
1483   mlir::Value shape = getShape();
1484   auto shapeArrayType = mlir::cast<fir::SequenceType>(
1485       hlfir::getFortranElementOrSequenceType(shape.getType()));
1486   if (shapeArrayType.getDimension() != 1)
1487     return emitOpError("SHAPE must be an array of rank 1");
1488   if (!mlir::isa<mlir::IntegerType>(shapeArrayType.getElementType()))
1489     return emitOpError("SHAPE must be an integer array");
1490   if (shapeArrayType.hasDynamicExtents())
1491     return emitOpError("SHAPE must have known size");
1492   if (shapeArrayType.getConstantArraySize() != resultType.getRank())
1493     return emitOpError("SHAPE's extent must match the result rank");
1494 
1495   if (mlir::Value pad = getPad()) {
1496     auto padArrayType = mlir::cast<fir::SequenceType>(
1497         hlfir::getFortranElementOrSequenceType(pad.getType()));
1498     if (auto match = areMatchingTypes(*this, arrayType.getElementType(),
1499                                       padArrayType.getElementType(),
1500                                       /*allowCharacterLenMismatch=*/true);
1501         match.failed())
1502       return emitOpError("ARRAY and PAD must be of the same type");
1503   }
1504 
1505   if (mlir::Value order = getOrder()) {
1506     auto orderArrayType = mlir::cast<fir::SequenceType>(
1507         hlfir::getFortranElementOrSequenceType(order.getType()));
1508     if (orderArrayType.getDimension() != 1)
1509       return emitOpError("ORDER must be an array of rank 1");
1510     if (!mlir::isa<mlir::IntegerType>(orderArrayType.getElementType()))
1511       return emitOpError("ORDER must be an integer array");
1512   }
1513 
1514   return mlir::success();
1515 }
1516 
1517 void hlfir::ReshapeOp::getEffects(
1518     llvm::SmallVectorImpl<
1519         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1520         &effects) {
1521   getIntrinsicEffects(getOperation(), effects);
1522 }
1523 
1524 //===----------------------------------------------------------------------===//
1525 // AssociateOp
1526 //===----------------------------------------------------------------------===//
1527 
1528 void hlfir::AssociateOp::build(mlir::OpBuilder &builder,
1529                                mlir::OperationState &result, mlir::Value source,
1530                                llvm::StringRef uniq_name, mlir::Value shape,
1531                                mlir::ValueRange typeparams,
1532                                fir::FortranVariableFlagsAttr fortran_attrs) {
1533   auto nameAttr = builder.getStringAttr(uniq_name);
1534   mlir::Type dataType = getFortranElementOrSequenceType(source.getType());
1535 
1536   // Preserve polymorphism of polymorphic expr.
1537   mlir::Type firVarType;
1538   auto sourceExprType = mlir::dyn_cast<hlfir::ExprType>(source.getType());
1539   if (sourceExprType && sourceExprType.isPolymorphic())
1540     firVarType = fir::ClassType::get(fir::HeapType::get(dataType));
1541   else
1542     firVarType = fir::ReferenceType::get(dataType);
1543 
1544   mlir::Type hlfirVariableType =
1545       DeclareOp::getHLFIRVariableType(firVarType, /*hasExplicitLbs=*/false);
1546   mlir::Type i1Type = builder.getI1Type();
1547   build(builder, result, {hlfirVariableType, firVarType, i1Type}, source, shape,
1548         typeparams, nameAttr, fortran_attrs);
1549 }
1550 
1551 void hlfir::AssociateOp::build(
1552     mlir::OpBuilder &builder, mlir::OperationState &result, mlir::Value source,
1553     mlir::Value shape, mlir::ValueRange typeparams,
1554     fir::FortranVariableFlagsAttr fortran_attrs,
1555     llvm::ArrayRef<mlir::NamedAttribute> attributes) {
1556   mlir::Type dataType = getFortranElementOrSequenceType(source.getType());
1557 
1558   // Preserve polymorphism of polymorphic expr.
1559   mlir::Type firVarType;
1560   auto sourceExprType = mlir::dyn_cast<hlfir::ExprType>(source.getType());
1561   if (sourceExprType && sourceExprType.isPolymorphic())
1562     firVarType = fir::ClassType::get(fir::HeapType::get(dataType));
1563   else
1564     firVarType = fir::ReferenceType::get(dataType);
1565 
1566   mlir::Type hlfirVariableType =
1567       DeclareOp::getHLFIRVariableType(firVarType, /*hasExplicitLbs=*/false);
1568   mlir::Type i1Type = builder.getI1Type();
1569   build(builder, result, {hlfirVariableType, firVarType, i1Type}, source, shape,
1570         typeparams, {}, fortran_attrs);
1571   result.addAttributes(attributes);
1572 }
1573 
1574 //===----------------------------------------------------------------------===//
1575 // EndAssociateOp
1576 //===----------------------------------------------------------------------===//
1577 
1578 void hlfir::EndAssociateOp::build(mlir::OpBuilder &builder,
1579                                   mlir::OperationState &result,
1580                                   hlfir::AssociateOp associate) {
1581   mlir::Value hlfirBase = associate.getBase();
1582   mlir::Value firBase = associate.getFirBase();
1583   // If EndAssociateOp may need to initiate the deallocation
1584   // of allocatable components, it has to have access to the variable
1585   // definition, so we cannot use the FIR base as the operand.
1586   return build(builder, result,
1587                hlfir::mayHaveAllocatableComponent(hlfirBase.getType())
1588                    ? hlfirBase
1589                    : firBase,
1590                associate.getMustFreeStrorageFlag());
1591 }
1592 
1593 llvm::LogicalResult hlfir::EndAssociateOp::verify() {
1594   mlir::Value var = getVar();
1595   if (hlfir::mayHaveAllocatableComponent(var.getType()) &&
1596       !hlfir::isFortranEntity(var))
1597     return emitOpError("that requires components deallocation must have var "
1598                        "operand that is a Fortran entity");
1599 
1600   return mlir::success();
1601 }
1602 
1603 //===----------------------------------------------------------------------===//
1604 // AsExprOp
1605 //===----------------------------------------------------------------------===//
1606 
1607 void hlfir::AsExprOp::build(mlir::OpBuilder &builder,
1608                             mlir::OperationState &result, mlir::Value var,
1609                             mlir::Value mustFree) {
1610   mlir::Type resultType = hlfir::getExprType(var.getType());
1611   return build(builder, result, resultType, var, mustFree);
1612 }
1613 
1614 void hlfir::AsExprOp::getEffects(
1615     llvm::SmallVectorImpl<
1616         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
1617         &effects) {
1618   // this isn't a transformational intrinsic but follows the same pattern: it
1619   // creates a hlfir.expr and so needs to have an allocation effect, plus it
1620   // might have a pointer-like argument, in which case it has a read effect
1621   // upon those
1622   getIntrinsicEffects(getOperation(), effects);
1623 }
1624 
1625 //===----------------------------------------------------------------------===//
1626 // ElementalOp
1627 //===----------------------------------------------------------------------===//
1628 
1629 /// Common builder for ElementalOp and ElementalAddrOp to add the arguments and
1630 /// create the elemental body. Result and clean-up body must be handled in
1631 /// specific builders.
1632 template <typename Op>
1633 static void buildElemental(mlir::OpBuilder &builder,
1634                            mlir::OperationState &odsState, mlir::Value shape,
1635                            mlir::Value mold, mlir::ValueRange typeparams,
1636                            bool isUnordered) {
1637   odsState.addOperands(shape);
1638   if (mold)
1639     odsState.addOperands(mold);
1640   odsState.addOperands(typeparams);
1641   odsState.addAttribute(
1642       Op::getOperandSegmentSizesAttrName(odsState.name),
1643       builder.getDenseI32ArrayAttr({/*shape=*/1, (mold ? 1 : 0),
1644                                     static_cast<int32_t>(typeparams.size())}));
1645   if (isUnordered)
1646     odsState.addAttribute(Op::getUnorderedAttrName(odsState.name),
1647                           isUnordered ? builder.getUnitAttr() : nullptr);
1648   mlir::Region *bodyRegion = odsState.addRegion();
1649   bodyRegion->push_back(new mlir::Block{});
1650   if (auto shapeType = mlir::dyn_cast<fir::ShapeType>(shape.getType())) {
1651     unsigned dim = shapeType.getRank();
1652     mlir::Type indexType = builder.getIndexType();
1653     for (unsigned d = 0; d < dim; ++d)
1654       bodyRegion->front().addArgument(indexType, odsState.location);
1655   }
1656 }
1657 
1658 void hlfir::ElementalOp::build(mlir::OpBuilder &builder,
1659                                mlir::OperationState &odsState,
1660                                mlir::Type resultType, mlir::Value shape,
1661                                mlir::Value mold, mlir::ValueRange typeparams,
1662                                bool isUnordered) {
1663   odsState.addTypes(resultType);
1664   buildElemental<hlfir::ElementalOp>(builder, odsState, shape, mold, typeparams,
1665                                      isUnordered);
1666 }
1667 
1668 mlir::Value hlfir::ElementalOp::getElementEntity() {
1669   return mlir::cast<hlfir::YieldElementOp>(getBody()->back()).getElementValue();
1670 }
1671 
1672 llvm::LogicalResult hlfir::ElementalOp::verify() {
1673   mlir::Value mold = getMold();
1674   hlfir::ExprType resultType = mlir::cast<hlfir::ExprType>(getType());
1675   if (!!mold != resultType.isPolymorphic())
1676     return emitOpError("result must be polymorphic when mold is present "
1677                        "and vice versa");
1678 
1679   return mlir::success();
1680 }
1681 
1682 //===----------------------------------------------------------------------===//
1683 // ApplyOp
1684 //===----------------------------------------------------------------------===//
1685 
1686 void hlfir::ApplyOp::build(mlir::OpBuilder &builder,
1687                            mlir::OperationState &odsState, mlir::Value expr,
1688                            mlir::ValueRange indices,
1689                            mlir::ValueRange typeparams) {
1690   mlir::Type resultType = expr.getType();
1691   if (auto exprType = mlir::dyn_cast<hlfir::ExprType>(resultType))
1692     resultType = exprType.getElementExprType();
1693   build(builder, odsState, resultType, expr, indices, typeparams);
1694 }
1695 
1696 //===----------------------------------------------------------------------===//
1697 // NullOp
1698 //===----------------------------------------------------------------------===//
1699 
1700 void hlfir::NullOp::build(mlir::OpBuilder &builder,
1701                           mlir::OperationState &odsState) {
1702   return build(builder, odsState,
1703                fir::ReferenceType::get(builder.getNoneType()));
1704 }
1705 
1706 //===----------------------------------------------------------------------===//
1707 // DestroyOp
1708 //===----------------------------------------------------------------------===//
1709 
1710 llvm::LogicalResult hlfir::DestroyOp::verify() {
1711   if (mustFinalizeExpr()) {
1712     mlir::Value expr = getExpr();
1713     hlfir::ExprType exprTy = mlir::cast<hlfir::ExprType>(expr.getType());
1714     mlir::Type elemTy = hlfir::getFortranElementType(exprTy);
1715     if (!mlir::isa<fir::RecordType>(elemTy))
1716       return emitOpError(
1717           "the element type must be finalizable, when 'finalize' is set");
1718   }
1719 
1720   return mlir::success();
1721 }
1722 
1723 //===----------------------------------------------------------------------===//
1724 // CopyInOp
1725 //===----------------------------------------------------------------------===//
1726 
1727 void hlfir::CopyInOp::build(mlir::OpBuilder &builder,
1728                             mlir::OperationState &odsState, mlir::Value var,
1729                             mlir::Value tempBox, mlir::Value var_is_present) {
1730   return build(builder, odsState, {var.getType(), builder.getI1Type()}, var,
1731                tempBox, var_is_present);
1732 }
1733 
1734 //===----------------------------------------------------------------------===//
1735 // ShapeOfOp
1736 //===----------------------------------------------------------------------===//
1737 
1738 void hlfir::ShapeOfOp::build(mlir::OpBuilder &builder,
1739                              mlir::OperationState &result, mlir::Value expr) {
1740   hlfir::ExprType exprTy = mlir::cast<hlfir::ExprType>(expr.getType());
1741   mlir::Type type = fir::ShapeType::get(builder.getContext(), exprTy.getRank());
1742   build(builder, result, type, expr);
1743 }
1744 
1745 std::size_t hlfir::ShapeOfOp::getRank() {
1746   mlir::Type resTy = getResult().getType();
1747   fir::ShapeType shape = mlir::cast<fir::ShapeType>(resTy);
1748   return shape.getRank();
1749 }
1750 
1751 llvm::LogicalResult hlfir::ShapeOfOp::verify() {
1752   mlir::Value expr = getExpr();
1753   hlfir::ExprType exprTy = mlir::cast<hlfir::ExprType>(expr.getType());
1754   std::size_t exprRank = exprTy.getShape().size();
1755 
1756   if (exprRank == 0)
1757     return emitOpError("cannot get the shape of a shape-less expression");
1758 
1759   std::size_t shapeRank = getRank();
1760   if (shapeRank != exprRank)
1761     return emitOpError("result rank and expr rank do not match");
1762 
1763   return mlir::success();
1764 }
1765 
1766 llvm::LogicalResult
1767 hlfir::ShapeOfOp::canonicalize(ShapeOfOp shapeOf,
1768                                mlir::PatternRewriter &rewriter) {
1769   // if extent information is available at compile time, immediately fold the
1770   // hlfir.shape_of into a fir.shape
1771   mlir::Location loc = shapeOf.getLoc();
1772   hlfir::ExprType expr =
1773       mlir::cast<hlfir::ExprType>(shapeOf.getExpr().getType());
1774 
1775   mlir::Value shape = hlfir::genExprShape(rewriter, loc, expr);
1776   if (!shape)
1777     // shape information is not available at compile time
1778     return llvm::LogicalResult::failure();
1779 
1780   rewriter.replaceAllUsesWith(shapeOf.getResult(), shape);
1781   rewriter.eraseOp(shapeOf);
1782   return llvm::LogicalResult::success();
1783 }
1784 
1785 mlir::OpFoldResult hlfir::ShapeOfOp::fold(FoldAdaptor adaptor) {
1786   if (matchPattern(getExpr(), mlir::m_Op<hlfir::ElementalOp>())) {
1787     auto elementalOp =
1788         mlir::cast<hlfir::ElementalOp>(getExpr().getDefiningOp());
1789     return elementalOp.getShape();
1790   }
1791   return {};
1792 }
1793 
1794 //===----------------------------------------------------------------------===//
1795 // GetExtent
1796 //===----------------------------------------------------------------------===//
1797 
1798 void hlfir::GetExtentOp::build(mlir::OpBuilder &builder,
1799                                mlir::OperationState &result, mlir::Value shape,
1800                                unsigned dim) {
1801   mlir::Type indexTy = builder.getIndexType();
1802   mlir::IntegerAttr dimAttr = mlir::IntegerAttr::get(indexTy, dim);
1803   build(builder, result, indexTy, shape, dimAttr);
1804 }
1805 
1806 llvm::LogicalResult hlfir::GetExtentOp::verify() {
1807   fir::ShapeType shapeTy = mlir::cast<fir::ShapeType>(getShape().getType());
1808   std::uint64_t rank = shapeTy.getRank();
1809   llvm::APInt dim = getDim();
1810   if (dim.sge(rank))
1811     return emitOpError("dimension index out of bounds");
1812   return mlir::success();
1813 }
1814 
1815 //===----------------------------------------------------------------------===//
1816 // RegionAssignOp
1817 //===----------------------------------------------------------------------===//
1818 
1819 /// Add a fir.end terminator to a parsed region if it does not already has a
1820 /// terminator.
1821 static void ensureTerminator(mlir::Region &region, mlir::Builder &builder,
1822                              mlir::Location loc) {
1823   // Borrow YielOp::ensureTerminator MLIR generated implementation to add a
1824   // fir.end if there is no terminator. This has nothing to do with YielOp,
1825   // other than the fact that yieldOp has the
1826   // SingleBlocklicitTerminator<"fir::FirEndOp"> interface that
1827   // cannot be added on other HLFIR operations with several regions which are
1828   // not all terminated the same way.
1829   hlfir::YieldOp::ensureTerminator(region, builder, loc);
1830 }
1831 
1832 mlir::ParseResult hlfir::RegionAssignOp::parse(mlir::OpAsmParser &parser,
1833                                                mlir::OperationState &result) {
1834   mlir::Region &rhsRegion = *result.addRegion();
1835   if (parser.parseRegion(rhsRegion))
1836     return mlir::failure();
1837   mlir::Region &lhsRegion = *result.addRegion();
1838   if (parser.parseKeyword("to") || parser.parseRegion(lhsRegion))
1839     return mlir::failure();
1840   mlir::Region &userDefinedAssignmentRegion = *result.addRegion();
1841   if (succeeded(parser.parseOptionalKeyword("user_defined_assign"))) {
1842     mlir::OpAsmParser::Argument rhsArg, lhsArg;
1843     if (parser.parseLParen() || parser.parseArgument(rhsArg) ||
1844         parser.parseColon() || parser.parseType(rhsArg.type) ||
1845         parser.parseRParen() || parser.parseKeyword("to") ||
1846         parser.parseLParen() || parser.parseArgument(lhsArg) ||
1847         parser.parseColon() || parser.parseType(lhsArg.type) ||
1848         parser.parseRParen())
1849       return mlir::failure();
1850     if (parser.parseRegion(userDefinedAssignmentRegion, {rhsArg, lhsArg}))
1851       return mlir::failure();
1852     ensureTerminator(userDefinedAssignmentRegion, parser.getBuilder(),
1853                      result.location);
1854   }
1855   return mlir::success();
1856 }
1857 
1858 void hlfir::RegionAssignOp::print(mlir::OpAsmPrinter &p) {
1859   p << " ";
1860   p.printRegion(getRhsRegion(), /*printEntryBlockArgs=*/false,
1861                 /*printBlockTerminators=*/true);
1862   p << " to ";
1863   p.printRegion(getLhsRegion(), /*printEntryBlockArgs=*/false,
1864                 /*printBlockTerminators=*/true);
1865   if (!getUserDefinedAssignment().empty()) {
1866     p << " user_defined_assign ";
1867     mlir::Value userAssignmentRhs = getUserAssignmentRhs();
1868     mlir::Value userAssignmentLhs = getUserAssignmentLhs();
1869     p << " (" << userAssignmentRhs << ": " << userAssignmentRhs.getType()
1870       << ") to (";
1871     p << userAssignmentLhs << ": " << userAssignmentLhs.getType() << ") ";
1872     p.printRegion(getUserDefinedAssignment(), /*printEntryBlockArgs=*/false,
1873                   /*printBlockTerminators=*/false);
1874   }
1875 }
1876 
1877 static mlir::Operation *getTerminator(mlir::Region &region) {
1878   if (region.empty() || region.back().empty())
1879     return nullptr;
1880   return &region.back().back();
1881 }
1882 
1883 llvm::LogicalResult hlfir::RegionAssignOp::verify() {
1884   if (!mlir::isa_and_nonnull<hlfir::YieldOp>(getTerminator(getRhsRegion())))
1885     return emitOpError(
1886         "right-hand side region must be terminated by an hlfir.yield");
1887   if (!mlir::isa_and_nonnull<hlfir::YieldOp, hlfir::ElementalAddrOp>(
1888           getTerminator(getLhsRegion())))
1889     return emitOpError("left-hand side region must be terminated by an "
1890                        "hlfir.yield or hlfir.elemental_addr");
1891   return mlir::success();
1892 }
1893 
1894 //===----------------------------------------------------------------------===//
1895 // YieldOp
1896 //===----------------------------------------------------------------------===//
1897 
1898 static mlir::ParseResult parseYieldOpCleanup(mlir::OpAsmParser &parser,
1899                                              mlir::Region &cleanup) {
1900   if (succeeded(parser.parseOptionalKeyword("cleanup"))) {
1901     if (parser.parseRegion(cleanup, /*arguments=*/{},
1902                            /*argTypes=*/{}))
1903       return mlir::failure();
1904     hlfir::YieldOp::ensureTerminator(cleanup, parser.getBuilder(),
1905                                      parser.getBuilder().getUnknownLoc());
1906   }
1907   return mlir::success();
1908 }
1909 
1910 template <typename YieldOp>
1911 static void printYieldOpCleanup(mlir::OpAsmPrinter &p, YieldOp yieldOp,
1912                                 mlir::Region &cleanup) {
1913   if (!cleanup.empty()) {
1914     p << "cleanup ";
1915     p.printRegion(cleanup, /*printEntryBlockArgs=*/false,
1916                   /*printBlockTerminators=*/false);
1917   }
1918 }
1919 
1920 //===----------------------------------------------------------------------===//
1921 // ElementalAddrOp
1922 //===----------------------------------------------------------------------===//
1923 
1924 void hlfir::ElementalAddrOp::build(mlir::OpBuilder &builder,
1925                                    mlir::OperationState &odsState,
1926                                    mlir::Value shape, mlir::Value mold,
1927                                    mlir::ValueRange typeparams,
1928                                    bool isUnordered) {
1929   buildElemental<hlfir::ElementalAddrOp>(builder, odsState, shape, mold,
1930                                          typeparams, isUnordered);
1931   // Push cleanUp region.
1932   odsState.addRegion();
1933 }
1934 
1935 llvm::LogicalResult hlfir::ElementalAddrOp::verify() {
1936   hlfir::YieldOp yieldOp =
1937       mlir::dyn_cast_or_null<hlfir::YieldOp>(getTerminator(getBody()));
1938   if (!yieldOp)
1939     return emitOpError("body region must be terminated by an hlfir.yield");
1940   mlir::Type elementAddrType = yieldOp.getEntity().getType();
1941   if (!hlfir::isFortranVariableType(elementAddrType) ||
1942       mlir::isa<fir::SequenceType>(
1943           hlfir::getFortranElementOrSequenceType(elementAddrType)))
1944     return emitOpError("body must compute the address of a scalar entity");
1945   unsigned shapeRank =
1946       mlir::cast<fir::ShapeType>(getShape().getType()).getRank();
1947   if (shapeRank != getIndices().size())
1948     return emitOpError("body number of indices must match shape rank");
1949   return mlir::success();
1950 }
1951 
1952 hlfir::YieldOp hlfir::ElementalAddrOp::getYieldOp() {
1953   hlfir::YieldOp yieldOp =
1954       mlir::dyn_cast_or_null<hlfir::YieldOp>(getTerminator(getBody()));
1955   assert(yieldOp && "element_addr is ill-formed");
1956   return yieldOp;
1957 }
1958 
1959 mlir::Value hlfir::ElementalAddrOp::getElementEntity() {
1960   return getYieldOp().getEntity();
1961 }
1962 
1963 mlir::Region *hlfir::ElementalAddrOp::getElementCleanup() {
1964   mlir::Region *cleanup = &getYieldOp().getCleanup();
1965   return cleanup->empty() ? nullptr : cleanup;
1966 }
1967 
1968 //===----------------------------------------------------------------------===//
1969 // OrderedAssignmentTreeOpInterface
1970 //===----------------------------------------------------------------------===//
1971 
1972 llvm::LogicalResult hlfir::OrderedAssignmentTreeOpInterface::verifyImpl() {
1973   if (mlir::Region *body = getSubTreeRegion())
1974     if (!body->empty())
1975       for (mlir::Operation &op : body->front())
1976         if (!mlir::isa<hlfir::OrderedAssignmentTreeOpInterface, fir::FirEndOp>(
1977                 op))
1978           return emitOpError(
1979               "body region must only contain OrderedAssignmentTreeOpInterface "
1980               "operations or fir.end");
1981   return mlir::success();
1982 }
1983 
1984 //===----------------------------------------------------------------------===//
1985 // ForallOp
1986 //===----------------------------------------------------------------------===//
1987 
1988 static mlir::ParseResult parseForallOpBody(mlir::OpAsmParser &parser,
1989                                            mlir::Region &body) {
1990   mlir::OpAsmParser::Argument bodyArg;
1991   if (parser.parseLParen() || parser.parseArgument(bodyArg) ||
1992       parser.parseColon() || parser.parseType(bodyArg.type) ||
1993       parser.parseRParen())
1994     return mlir::failure();
1995   if (parser.parseRegion(body, {bodyArg}))
1996     return mlir::failure();
1997   ensureTerminator(body, parser.getBuilder(),
1998                    parser.getBuilder().getUnknownLoc());
1999   return mlir::success();
2000 }
2001 
2002 static void printForallOpBody(mlir::OpAsmPrinter &p, hlfir::ForallOp forall,
2003                               mlir::Region &body) {
2004   mlir::Value forallIndex = forall.getForallIndexValue();
2005   p << " (" << forallIndex << ": " << forallIndex.getType() << ") ";
2006   p.printRegion(body, /*printEntryBlockArgs=*/false,
2007                 /*printBlockTerminators=*/false);
2008 }
2009 
2010 /// Predicate implementation of YieldIntegerOrEmpty.
2011 static bool yieldsIntegerOrEmpty(mlir::Region &region) {
2012   if (region.empty())
2013     return true;
2014   auto yield = mlir::dyn_cast_or_null<hlfir::YieldOp>(getTerminator(region));
2015   return yield && fir::isa_integer(yield.getEntity().getType());
2016 }
2017 
2018 //===----------------------------------------------------------------------===//
2019 // ForallMaskOp
2020 //===----------------------------------------------------------------------===//
2021 
2022 static mlir::ParseResult parseAssignmentMaskOpBody(mlir::OpAsmParser &parser,
2023                                                    mlir::Region &body) {
2024   if (parser.parseRegion(body))
2025     return mlir::failure();
2026   ensureTerminator(body, parser.getBuilder(),
2027                    parser.getBuilder().getUnknownLoc());
2028   return mlir::success();
2029 }
2030 
2031 template <typename ConcreteOp>
2032 static void printAssignmentMaskOpBody(mlir::OpAsmPrinter &p, ConcreteOp,
2033                                       mlir::Region &body) {
2034   // ElseWhereOp is a WhereOp/ElseWhereOp terminator that should be printed.
2035   bool printBlockTerminators =
2036       !body.empty() &&
2037       mlir::isa_and_nonnull<hlfir::ElseWhereOp>(body.back().getTerminator());
2038   p.printRegion(body, /*printEntryBlockArgs=*/false, printBlockTerminators);
2039 }
2040 
2041 static bool yieldsLogical(mlir::Region &region, bool mustBeScalarI1) {
2042   if (region.empty())
2043     return false;
2044   auto yield = mlir::dyn_cast_or_null<hlfir::YieldOp>(getTerminator(region));
2045   if (!yield)
2046     return false;
2047   mlir::Type yieldType = yield.getEntity().getType();
2048   if (mustBeScalarI1)
2049     return hlfir::isI1Type(yieldType);
2050   return hlfir::isMaskArgument(yieldType) &&
2051          mlir::isa<fir::SequenceType>(
2052              hlfir::getFortranElementOrSequenceType(yieldType));
2053 }
2054 
2055 llvm::LogicalResult hlfir::ForallMaskOp::verify() {
2056   if (!yieldsLogical(getMaskRegion(), /*mustBeScalarI1=*/true))
2057     return emitOpError("mask region must yield a scalar i1");
2058   mlir::Operation *op = getOperation();
2059   hlfir::ForallOp forallOp =
2060       mlir::dyn_cast_or_null<hlfir::ForallOp>(op->getParentOp());
2061   if (!forallOp || op->getParentRegion() != &forallOp.getBody())
2062     return emitOpError("must be inside the body region of an hlfir.forall");
2063   return mlir::success();
2064 }
2065 
2066 //===----------------------------------------------------------------------===//
2067 // WhereOp and ElseWhereOp
2068 //===----------------------------------------------------------------------===//
2069 
2070 template <typename ConcreteOp>
2071 static llvm::LogicalResult verifyWhereAndElseWhereBody(ConcreteOp &concreteOp) {
2072   for (mlir::Operation &op : concreteOp.getBody().front())
2073     if (mlir::isa<hlfir::ForallOp>(op))
2074       return concreteOp.emitOpError(
2075           "body region must not contain hlfir.forall");
2076   return mlir::success();
2077 }
2078 
2079 llvm::LogicalResult hlfir::WhereOp::verify() {
2080   if (!yieldsLogical(getMaskRegion(), /*mustBeScalarI1=*/false))
2081     return emitOpError("mask region must yield a logical array");
2082   return verifyWhereAndElseWhereBody(*this);
2083 }
2084 
2085 llvm::LogicalResult hlfir::ElseWhereOp::verify() {
2086   if (!getMaskRegion().empty())
2087     if (!yieldsLogical(getMaskRegion(), /*mustBeScalarI1=*/false))
2088       return emitOpError(
2089           "mask region must yield a logical array when provided");
2090   return verifyWhereAndElseWhereBody(*this);
2091 }
2092 
2093 //===----------------------------------------------------------------------===//
2094 // ForallIndexOp
2095 //===----------------------------------------------------------------------===//
2096 
2097 llvm::LogicalResult
2098 hlfir::ForallIndexOp::canonicalize(hlfir::ForallIndexOp indexOp,
2099                                    mlir::PatternRewriter &rewriter) {
2100   for (mlir::Operation *user : indexOp->getResult(0).getUsers())
2101     if (!mlir::isa<fir::LoadOp>(user))
2102       return mlir::failure();
2103 
2104   auto insertPt = rewriter.saveInsertionPoint();
2105   llvm::SmallVector<mlir::Operation *> users(indexOp->getResult(0).getUsers());
2106   for (mlir::Operation *user : users)
2107     if (auto loadOp = mlir::dyn_cast<fir::LoadOp>(user)) {
2108       rewriter.setInsertionPoint(loadOp);
2109       rewriter.replaceOpWithNewOp<fir::ConvertOp>(
2110           user, loadOp.getResult().getType(), indexOp.getIndex());
2111     }
2112   rewriter.restoreInsertionPoint(insertPt);
2113   rewriter.eraseOp(indexOp);
2114   return mlir::success();
2115 }
2116 
2117 //===----------------------------------------------------------------------===//
2118 // CharExtremumOp
2119 //===----------------------------------------------------------------------===//
2120 
2121 llvm::LogicalResult hlfir::CharExtremumOp::verify() {
2122   if (getStrings().size() < 2)
2123     return emitOpError("must be provided at least two string operands");
2124   unsigned kind = getCharacterKind(getResult().getType());
2125   for (auto string : getStrings())
2126     if (kind != getCharacterKind(string.getType()))
2127       return emitOpError("strings must have the same KIND as the result type");
2128   return mlir::success();
2129 }
2130 
2131 void hlfir::CharExtremumOp::build(mlir::OpBuilder &builder,
2132                                   mlir::OperationState &result,
2133                                   hlfir::CharExtremumPredicate predicate,
2134                                   mlir::ValueRange strings) {
2135 
2136   fir::CharacterType::LenType resultTypeLen = 0;
2137   assert(!strings.empty() && "must contain operands");
2138   unsigned kind = getCharacterKind(strings[0].getType());
2139   for (auto string : strings)
2140     if (auto cstLen = getCharacterLengthIfStatic(string.getType())) {
2141       resultTypeLen = std::max(resultTypeLen, *cstLen);
2142     } else {
2143       resultTypeLen = fir::CharacterType::unknownLen();
2144       break;
2145     }
2146   auto resultType = hlfir::ExprType::get(
2147       builder.getContext(), hlfir::ExprType::Shape{},
2148       fir::CharacterType::get(builder.getContext(), kind, resultTypeLen),
2149       false);
2150 
2151   build(builder, result, resultType, predicate, strings);
2152 }
2153 
2154 void hlfir::CharExtremumOp::getEffects(
2155     llvm::SmallVectorImpl<
2156         mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
2157         &effects) {
2158   getIntrinsicEffects(getOperation(), effects);
2159 }
2160 
2161 //===----------------------------------------------------------------------===//
2162 // GetLength
2163 //===----------------------------------------------------------------------===//
2164 
2165 llvm::LogicalResult
2166 hlfir::GetLengthOp::canonicalize(GetLengthOp getLength,
2167                                  mlir::PatternRewriter &rewriter) {
2168   mlir::Location loc = getLength.getLoc();
2169   auto exprTy = mlir::cast<hlfir::ExprType>(getLength.getExpr().getType());
2170   auto charTy = mlir::cast<fir::CharacterType>(exprTy.getElementType());
2171   if (!charTy.hasConstantLen())
2172     return mlir::failure();
2173 
2174   mlir::Type indexTy = rewriter.getIndexType();
2175   auto cstLen = rewriter.create<mlir::arith::ConstantOp>(
2176       loc, indexTy, mlir::IntegerAttr::get(indexTy, charTy.getLen()));
2177   rewriter.replaceOp(getLength, cstLen);
2178   return mlir::success();
2179 }
2180 
2181 //===----------------------------------------------------------------------===//
2182 // EvaluateInMemoryOp
2183 //===----------------------------------------------------------------------===//
2184 
2185 void hlfir::EvaluateInMemoryOp::build(mlir::OpBuilder &builder,
2186                                       mlir::OperationState &odsState,
2187                                       mlir::Type resultType, mlir::Value shape,
2188                                       mlir::ValueRange typeparams) {
2189   odsState.addTypes(resultType);
2190   if (shape)
2191     odsState.addOperands(shape);
2192   odsState.addOperands(typeparams);
2193   odsState.addAttribute(
2194       getOperandSegmentSizeAttr(),
2195       builder.getDenseI32ArrayAttr(
2196           {shape ? 1 : 0, static_cast<int32_t>(typeparams.size())}));
2197   mlir::Region *bodyRegion = odsState.addRegion();
2198   bodyRegion->push_back(new mlir::Block{});
2199   mlir::Type memType = fir::ReferenceType::get(
2200       hlfir::getFortranElementOrSequenceType(resultType));
2201   bodyRegion->front().addArgument(memType, odsState.location);
2202   EvaluateInMemoryOp::ensureTerminator(*bodyRegion, builder, odsState.location);
2203 }
2204 
2205 llvm::LogicalResult hlfir::EvaluateInMemoryOp::verify() {
2206   unsigned shapeRank = 0;
2207   if (mlir::Value shape = getShape())
2208     if (auto shapeTy = mlir::dyn_cast<fir::ShapeType>(shape.getType()))
2209       shapeRank = shapeTy.getRank();
2210   auto exprType = mlir::cast<hlfir::ExprType>(getResult().getType());
2211   if (shapeRank != exprType.getRank())
2212     return emitOpError("`shape` rank must match the result rank");
2213   mlir::Type elementType = exprType.getElementType();
2214   if (auto res = verifyTypeparams(*this, elementType, getTypeparams().size());
2215       failed(res))
2216     return res;
2217   return mlir::success();
2218 }
2219 
2220 #include "flang/Optimizer/HLFIR/HLFIROpInterfaces.cpp.inc"
2221 #define GET_OP_CLASSES
2222 #include "flang/Optimizer/HLFIR/HLFIREnums.cpp.inc"
2223 #include "flang/Optimizer/HLFIR/HLFIROps.cpp.inc"
2224