1 //===-- Optimizer/Dialect/FIRType.h -- FIR types ----------------*- C++ -*-===// 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 #ifndef FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H 14 #define FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H 15 16 #include "mlir/IR/BuiltinAttributes.h" 17 #include "mlir/IR/BuiltinTypes.h" 18 #include "mlir/Interfaces/DataLayoutInterfaces.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/IR/Type.h" 21 22 namespace fir { 23 class FIROpsDialect; 24 class KindMapping; 25 using KindTy = unsigned; 26 27 namespace detail { 28 struct RecordTypeStorage; 29 } // namespace detail 30 31 } // namespace fir 32 33 //===----------------------------------------------------------------------===// 34 // BaseBoxType 35 //===----------------------------------------------------------------------===// 36 37 namespace fir { 38 39 /// This class provides a shared interface for box and class types. 40 class BaseBoxType : public mlir::Type { 41 public: 42 using mlir::Type::Type; 43 44 /// Box attributes. 45 enum class Attribute { None, Allocatable, Pointer }; 46 47 /// Returns the element type of this box type. 48 mlir::Type getEleTy() const; 49 50 /// Unwrap element type from fir.heap, fir.ptr and fir.array. 51 mlir::Type unwrapInnerType() const; 52 53 /// Is this the box for an assumed rank? 54 bool isAssumedRank() const; 55 56 /// Return the same type, except for the shape, that is taken the shape 57 /// of shapeMold. 58 BaseBoxType getBoxTypeWithNewShape(mlir::Type shapeMold) const; 59 BaseBoxType getBoxTypeWithNewShape(int rank) const; 60 61 /// Return the same type, except for the attribute (fir.heap/fir.ptr). 62 BaseBoxType getBoxTypeWithNewAttr(Attribute attr) const; 63 64 /// Methods for support type inquiry through isa, cast, and dyn_cast. 65 static bool classof(mlir::Type type); 66 }; 67 68 } // namespace fir 69 70 #define GET_TYPEDEF_CLASSES 71 #include "flang/Optimizer/Dialect/FIROpsTypes.h.inc" 72 73 namespace llvm { 74 class raw_ostream; 75 class StringRef; 76 template <typename> 77 class ArrayRef; 78 class hash_code; 79 } // namespace llvm 80 81 namespace mlir { 82 class DialectAsmParser; 83 class DialectAsmPrinter; 84 class ComplexType; 85 class FloatType; 86 class ValueRange; 87 } // namespace mlir 88 89 namespace fir { 90 namespace detail { 91 struct RecordTypeStorage; 92 } // namespace detail 93 94 // These isa_ routines follow the precedent of llvm::isa_or_null<> 95 96 /// Is `t` any of the FIR dialect types? 97 bool isa_fir_type(mlir::Type t); 98 99 /// Is `t` any of the Standard dialect types? 100 bool isa_std_type(mlir::Type t); 101 102 /// Is `t` any of the FIR dialect or Standard dialect types? 103 bool isa_fir_or_std_type(mlir::Type t); 104 105 /// Is `t` a FIR dialect type that implies a memory (de)reference? 106 inline bool isa_ref_type(mlir::Type t) { 107 return mlir::isa<fir::ReferenceType, fir::PointerType, fir::HeapType, 108 fir::LLVMPointerType>(t); 109 } 110 111 /// Is `t` a boxed type? 112 inline bool isa_box_type(mlir::Type t) { 113 return mlir::isa<fir::BaseBoxType, fir::BoxCharType, fir::BoxProcType>(t); 114 } 115 116 /// Is `t` a type that is always trivially pass-by-reference? Specifically, this 117 /// is testing if `t` is a ReferenceType or any box type. Compare this to 118 /// conformsWithPassByRef(), which includes pointers and allocatables. 119 inline bool isa_passbyref_type(mlir::Type t) { 120 return mlir::isa<fir::ReferenceType, mlir::FunctionType>(t) || 121 isa_box_type(t); 122 } 123 124 /// Is `t` a type that can conform to be pass-by-reference? Depending on the 125 /// context, these types may simply demote to pass-by-reference or a reference 126 /// to them may have to be passed instead. Functions are always referent. 127 inline bool conformsWithPassByRef(mlir::Type t) { 128 return isa_ref_type(t) || isa_box_type(t) || mlir::isa<mlir::FunctionType>(t); 129 } 130 131 /// Is `t` a derived (record) type? 132 inline bool isa_derived(mlir::Type t) { return mlir::isa<fir::RecordType>(t); } 133 134 /// Is `t` type(c_ptr) or type(c_funptr)? 135 inline bool isa_builtin_cptr_type(mlir::Type t) { 136 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(t)) 137 return recTy.getName().ends_with("T__builtin_c_ptr") || 138 recTy.getName().ends_with("T__builtin_c_funptr"); 139 return false; 140 } 141 142 // Is `t` type(c_devptr)? 143 inline bool isa_builtin_c_devptr_type(mlir::Type t) { 144 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(t)) 145 return recTy.getName().ends_with("T__builtin_c_devptr"); 146 return false; 147 } 148 149 /// Is `t` type(c_devptr)? 150 inline bool isa_builtin_cdevptr_type(mlir::Type t) { 151 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(t)) 152 return recTy.getName().ends_with("T__builtin_c_devptr"); 153 return false; 154 } 155 156 /// Is `t` a FIR dialect aggregate type? 157 inline bool isa_aggregate(mlir::Type t) { 158 return mlir::isa<SequenceType, mlir::TupleType>(t) || fir::isa_derived(t); 159 } 160 161 /// Extract the `Type` pointed to from a FIR memory reference type. If `t` is 162 /// not a memory reference type, then returns a null `Type`. 163 mlir::Type dyn_cast_ptrEleTy(mlir::Type t); 164 165 /// Extract the `Type` pointed to from a FIR memory reference or box type. If 166 /// `t` is not a memory reference or box type, then returns a null `Type`. 167 mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t); 168 169 /// Is `t` a real type? 170 inline bool isa_real(mlir::Type t) { return mlir::isa<mlir::FloatType>(t); } 171 172 /// Is `t` an integral type? 173 inline bool isa_integer(mlir::Type t) { 174 return mlir::isa<mlir::IndexType, mlir::IntegerType, fir::IntegerType>(t); 175 } 176 177 /// Is `t` a vector type? 178 inline bool isa_vector(mlir::Type t) { 179 return mlir::isa<mlir::VectorType, fir::VectorType>(t); 180 } 181 182 mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser); 183 184 void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p); 185 186 /// Guarantee `type` is a scalar integral type (standard Integer, standard 187 /// Index, or FIR Int). Aborts execution if condition is false. 188 void verifyIntegralType(mlir::Type type); 189 190 /// Is `t` a floating point complex type? 191 inline bool isa_complex(mlir::Type t) { 192 return mlir::isa<mlir::ComplexType>(t) && 193 mlir::isa<mlir::FloatType>( 194 mlir::cast<mlir::ComplexType>(t).getElementType()); 195 } 196 197 /// Is `t` a CHARACTER type? Does not check the length. 198 inline bool isa_char(mlir::Type t) { return mlir::isa<fir::CharacterType>(t); } 199 200 /// Is `t` a trivial intrinsic type? CHARACTER is <em>excluded</em> because it 201 /// is a dependent type. 202 inline bool isa_trivial(mlir::Type t) { 203 return isa_integer(t) || isa_real(t) || isa_complex(t) || isa_vector(t) || 204 mlir::isa<fir::LogicalType>(t); 205 } 206 207 /// Is `t` a CHARACTER type with a LEN other than 1? 208 inline bool isa_char_string(mlir::Type t) { 209 if (auto ct = mlir::dyn_cast_or_null<fir::CharacterType>(t)) 210 return ct.getLen() != fir::CharacterType::singleton(); 211 return false; 212 } 213 214 /// Is `t` a box type for which it is not possible to deduce the box size? 215 /// It is not possible to deduce the size of a box that describes an entity 216 /// of unknown rank. 217 /// Unknown type are always considered to have the size of derived type box 218 /// (since they may hold one), and are not considered to be unknown size. 219 bool isa_unknown_size_box(mlir::Type t); 220 221 /// Returns true iff `t` is a fir.char type and has an unknown length. 222 inline bool characterWithDynamicLen(mlir::Type t) { 223 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(t)) 224 return charTy.hasDynamicLen(); 225 return false; 226 } 227 228 /// Returns true iff `seqTy` has either an unknown shape or a non-constant shape 229 /// (where rank > 0). 230 inline bool sequenceWithNonConstantShape(fir::SequenceType seqTy) { 231 return seqTy.hasUnknownShape() || seqTy.hasDynamicExtents(); 232 } 233 234 /// Returns true iff the type `t` does not have a constant size. 235 bool hasDynamicSize(mlir::Type t); 236 237 inline unsigned getRankOfShapeType(mlir::Type t) { 238 if (auto shTy = mlir::dyn_cast<fir::ShapeType>(t)) 239 return shTy.getRank(); 240 if (auto shTy = mlir::dyn_cast<fir::ShapeShiftType>(t)) 241 return shTy.getRank(); 242 if (auto shTy = mlir::dyn_cast<fir::ShiftType>(t)) 243 return shTy.getRank(); 244 return 0; 245 } 246 247 /// Get the memory reference type of the data pointer from the box type, 248 inline mlir::Type boxMemRefType(fir::BaseBoxType t) { 249 auto eleTy = t.getEleTy(); 250 if (!mlir::isa<fir::PointerType, fir::HeapType>(eleTy)) 251 eleTy = fir::ReferenceType::get(t); 252 return eleTy; 253 } 254 255 /// If `t` is a SequenceType return its element type, otherwise return `t`. 256 inline mlir::Type unwrapSequenceType(mlir::Type t) { 257 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(t)) 258 return seqTy.getEleTy(); 259 return t; 260 } 261 262 /// Return the nested sequence type if any. 263 mlir::Type extractSequenceType(mlir::Type ty); 264 265 inline mlir::Type unwrapRefType(mlir::Type t) { 266 if (auto eleTy = dyn_cast_ptrEleTy(t)) 267 return eleTy; 268 return t; 269 } 270 271 /// If `t` conforms with a pass-by-reference type (box, ref, ptr, etc.) then 272 /// return the element type of `t`. Otherwise, return `t`. 273 inline mlir::Type unwrapPassByRefType(mlir::Type t) { 274 if (auto eleTy = dyn_cast_ptrOrBoxEleTy(t)) 275 return eleTy; 276 return t; 277 } 278 279 /// Unwrap either a sequence or a boxed sequence type, returning the element 280 /// type of the sequence type. 281 /// e.g., 282 /// !fir.array<...xT> -> T 283 /// !fir.box<!fir.ptr<!fir.array<...xT>>> -> T 284 /// otherwise 285 /// T -> T 286 mlir::Type unwrapSeqOrBoxedSeqType(mlir::Type ty); 287 288 /// Unwrap all referential and sequential outer types (if any). Returns the 289 /// element type. This is useful for determining the element type of any object 290 /// memory reference, whether it is a single instance or a series of instances. 291 mlir::Type unwrapAllRefAndSeqType(mlir::Type ty); 292 293 /// Unwrap all pointer and box types and return the element type if it is a 294 /// sequence type, otherwise return null. 295 inline fir::SequenceType unwrapUntilSeqType(mlir::Type t) { 296 while (true) { 297 if (!t) 298 return {}; 299 if (auto ty = dyn_cast_ptrOrBoxEleTy(t)) { 300 t = ty; 301 continue; 302 } 303 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(t)) 304 return seqTy; 305 return {}; 306 } 307 } 308 309 /// Unwrap the referential and sequential outer types (if any). Returns the 310 /// the element if type is fir::RecordType 311 inline fir::RecordType unwrapIfDerived(fir::BaseBoxType boxTy) { 312 return mlir::dyn_cast<fir::RecordType>( 313 fir::unwrapSequenceType(fir::unwrapRefType(boxTy.getEleTy()))); 314 } 315 316 /// Return true iff `boxTy` wraps a fir::RecordType with length parameters 317 inline bool isDerivedTypeWithLenParams(fir::BaseBoxType boxTy) { 318 auto recTy = unwrapIfDerived(boxTy); 319 return recTy && recTy.getNumLenParams() > 0; 320 } 321 322 /// Return true iff `boxTy` wraps a fir::RecordType 323 inline bool isDerivedType(fir::BaseBoxType boxTy) { 324 return static_cast<bool>(unwrapIfDerived(boxTy)); 325 } 326 327 #ifndef NDEBUG 328 // !fir.ptr<X> and !fir.heap<X> where X is !fir.ptr, !fir.heap, or !fir.ref 329 // is undefined and disallowed. 330 inline bool singleIndirectionLevel(mlir::Type ty) { 331 return !fir::isa_ref_type(ty); 332 } 333 #endif 334 335 /// Return true iff `ty` is the type of a POINTER entity or value. 336 /// `isa_ref_type()` can be used to distinguish. 337 bool isPointerType(mlir::Type ty); 338 339 /// Return true iff `ty` is the type of an ALLOCATABLE entity or value. 340 bool isAllocatableType(mlir::Type ty); 341 342 /// Return true iff `ty` is !fir.box<none>. 343 bool isBoxNone(mlir::Type ty); 344 345 /// Return true iff `ty` is the type of a boxed record type. 346 /// e.g. !fir.box<!fir.type<derived>> 347 bool isBoxedRecordType(mlir::Type ty); 348 349 /// Return true iff `ty` is a type that contains descriptor information. 350 bool isTypeWithDescriptor(mlir::Type ty); 351 352 /// Return true iff `ty` is a scalar boxed record type. 353 /// e.g. !fir.box<!fir.type<derived>> 354 /// !fir.box<!fir.heap<!fir.type<derived>>> 355 /// !fir.class<!fir.type<derived>> 356 bool isScalarBoxedRecordType(mlir::Type ty); 357 358 /// Return the nested RecordType if one if found. Return ty otherwise. 359 mlir::Type getDerivedType(mlir::Type ty); 360 361 /// Return true iff `ty` is the type of an polymorphic entity or 362 /// value. 363 bool isPolymorphicType(mlir::Type ty); 364 365 /// Return true iff `ty` is the type of an unlimited polymorphic entity or 366 /// value. 367 bool isUnlimitedPolymorphicType(mlir::Type ty); 368 369 /// Return true iff `ty` is the type of an assumed type. In FIR, 370 /// assumed types are of the form `[fir.ref|ptr|heap]fir.box<[fir.array]none>`, 371 /// or `fir.ref|ptr|heap<[fir.array]none>`. 372 bool isAssumedType(mlir::Type ty); 373 374 /// Return true iff `ty` is the type of an assumed shape array. 375 bool isAssumedShape(mlir::Type ty); 376 377 /// Return true iff `ty` is the type of an allocatable array. 378 bool isAllocatableOrPointerArray(mlir::Type ty); 379 380 /// Return true iff `boxTy` wraps a record type or an unlimited polymorphic 381 /// entity. Polymorphic entities with intrinsic type spec do not have addendum 382 inline bool boxHasAddendum(fir::BaseBoxType boxTy) { 383 return static_cast<bool>(unwrapIfDerived(boxTy)) || 384 fir::isUnlimitedPolymorphicType(boxTy); 385 } 386 387 /// Get the rank from a !fir.box type. 388 unsigned getBoxRank(mlir::Type boxTy); 389 390 /// Return the inner type of the given type. 391 mlir::Type unwrapInnerType(mlir::Type ty); 392 393 /// Return true iff `ty` is a RecordType with members that are allocatable. 394 bool isRecordWithAllocatableMember(mlir::Type ty); 395 396 /// Return true iff `ty` is a scalar/array of RecordType 397 /// with members that are descriptors. 398 bool isRecordWithDescriptorMember(mlir::Type ty); 399 400 /// Return true iff `ty` is a RecordType with type parameters. 401 inline bool isRecordWithTypeParameters(mlir::Type ty) { 402 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(ty)) 403 return recTy.isDependentType(); 404 return false; 405 } 406 407 /// Is this tuple type holding a character function and its result length? 408 bool isCharacterProcedureTuple(mlir::Type type, bool acceptRawFunc = true); 409 410 /// Apply the components specified by `path` to `rootTy` to determine the type 411 /// of the resulting component element. `rootTy` should be an aggregate type. 412 /// Returns null on error. 413 mlir::Type applyPathToType(mlir::Type rootTy, mlir::ValueRange path); 414 415 /// Does this function type has a result that requires binding the result value 416 /// with a storage in a fir.save_result operation in order to use the result? 417 bool hasAbstractResult(mlir::FunctionType ty); 418 419 /// Convert llvm::Type::TypeID to mlir::Type 420 mlir::Type fromRealTypeID(mlir::MLIRContext *context, llvm::Type::TypeID typeID, 421 fir::KindTy kind); 422 423 int getTypeCode(mlir::Type ty, const KindMapping &kindMap); 424 425 inline bool BaseBoxType::classof(mlir::Type type) { 426 return mlir::isa<fir::BoxType, fir::ClassType>(type); 427 } 428 429 /// Return true iff `ty` is none or fir.array<none>. 430 inline bool isNoneOrSeqNone(mlir::Type type) { 431 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type)) 432 return mlir::isa<mlir::NoneType>(seqTy.getEleTy()); 433 return mlir::isa<mlir::NoneType>(type); 434 } 435 436 /// Return a fir.box<T> or fir.class<T> if the type is polymorphic. If the type 437 /// is polymorphic and assumed shape return fir.box<T>. 438 inline mlir::Type wrapInClassOrBoxType(mlir::Type eleTy, 439 bool isPolymorphic = false, 440 bool isAssumedType = false) { 441 if (isPolymorphic && !isAssumedType) 442 return fir::ClassType::get(eleTy); 443 return fir::BoxType::get(eleTy); 444 } 445 446 /// Return the elementType where intrinsic types are replaced with none for 447 /// unlimited polymorphic entities. 448 /// 449 /// i32 -> () 450 /// !fir.array<2xf32> -> !fir.array<2xnone> 451 /// !fir.heap<!fir.array<2xf32>> -> !fir.heap<!fir.array<2xnone>> 452 inline mlir::Type updateTypeForUnlimitedPolymorphic(mlir::Type ty) { 453 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) 454 return fir::SequenceType::get( 455 seqTy.getShape(), updateTypeForUnlimitedPolymorphic(seqTy.getEleTy())); 456 if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty)) 457 return fir::HeapType::get( 458 updateTypeForUnlimitedPolymorphic(heapTy.getEleTy())); 459 if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(ty)) 460 return fir::PointerType::get( 461 updateTypeForUnlimitedPolymorphic(pointerTy.getEleTy())); 462 if (!mlir::isa<mlir::NoneType, fir::RecordType>(ty)) 463 return mlir::NoneType::get(ty.getContext()); 464 return ty; 465 } 466 467 /// Replace the element type of \p type by \p newElementType, preserving 468 /// all other layers of the type (fir.ref/ptr/heap/array/box/class). 469 /// If \p turnBoxIntoClass and the input is a fir.box, it will be turned into 470 /// a fir.class in the result. 471 mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType, 472 bool turnBoxIntoClass); 473 474 /// Is `t` an address to fir.box or class type? 475 inline bool isBoxAddress(mlir::Type t) { 476 return fir::isa_ref_type(t) && 477 mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(t)); 478 } 479 480 /// Is `t` a fir.box or class address or value type? 481 inline bool isBoxAddressOrValue(mlir::Type t) { 482 return mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(t)); 483 } 484 485 /// Is this a fir.boxproc address type? 486 inline bool isBoxProcAddressType(mlir::Type t) { 487 t = fir::dyn_cast_ptrEleTy(t); 488 return t && mlir::isa<fir::BoxProcType>(t); 489 } 490 491 /// Return a string representation of `ty`. 492 /// 493 /// fir.array<10x10xf32> -> prefix_10x10xf32 494 /// fir.ref<i32> -> prefix_ref_i32 495 std::string getTypeAsString(mlir::Type ty, const KindMapping &kindMap, 496 llvm::StringRef prefix = ""); 497 498 /// Return the size and alignment of FIR types. 499 /// TODO: consider moving this to a DataLayoutTypeInterface implementation 500 /// for FIR types. It should first be ensured that it is OK to open the gate of 501 /// target dependent type size inquiries in lowering. It would also not be 502 /// straightforward given the need for a kind map that would need to be 503 /// converted in terms of mlir::DataLayoutEntryKey. 504 505 /// This variant terminates the compilation if an unsupported type is passed. 506 std::pair<std::uint64_t, unsigned short> 507 getTypeSizeAndAlignmentOrCrash(mlir::Location loc, mlir::Type ty, 508 const mlir::DataLayout &dl, 509 const fir::KindMapping &kindMap); 510 511 /// This variant returns std::nullopt if an unsupported type is passed. 512 std::optional<std::pair<uint64_t, unsigned short>> 513 getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty, 514 const mlir::DataLayout &dl, 515 const fir::KindMapping &kindMap); 516 } // namespace fir 517 518 #endif // FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H 519