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 ®ion, 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 ®ion) { 1878 if (region.empty() || region.back().empty()) 1879 return nullptr; 1880 return ®ion.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 ®ion) { 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 ®ion, 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