| 1 | //===-- FIRType.cpp -------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "flang/Optimizer/Dialect/FIRType.h" |
| 14 | #include "flang/Common/ISO_Fortran_binding_wrapper.h" |
| 15 | #include "flang/Optimizer/Builder/Todo.h" |
| 16 | #include "flang/Optimizer/Dialect/FIRDialect.h" |
| 17 | #include "flang/Optimizer/Dialect/Support/KindMapping.h" |
| 18 | #include "flang/Tools/PointerModels.h" |
| 19 | #include "mlir/IR/Builders.h" |
| 20 | #include "mlir/IR/BuiltinDialect.h" |
| 21 | #include "mlir/IR/Diagnostics.h" |
| 22 | #include "mlir/IR/DialectImplementation.h" |
| 23 | #include "mlir/Support/LLVM.h" |
| 24 | #include "llvm/ADT/SmallPtrSet.h" |
| 25 | #include "llvm/ADT/StringSet.h" |
| 26 | #include "llvm/ADT/TypeSwitch.h" |
| 27 | #include "llvm/Support/ErrorHandling.h" |
| 28 | |
| 29 | #define GET_TYPEDEF_CLASSES |
| 30 | #include "flang/Optimizer/Dialect/FIROpsTypes.cpp.inc" |
| 31 | |
| 32 | using namespace fir; |
| 33 | |
| 34 | namespace { |
| 35 | |
| 36 | template <typename TYPE> |
| 37 | TYPE parseIntSingleton(mlir::AsmParser &parser) { |
| 38 | int kind = 0; |
| 39 | if (parser.parseLess() || parser.parseInteger(kind) || parser.parseGreater()) |
| 40 | return {}; |
| 41 | return TYPE::get(parser.getContext(), kind); |
| 42 | } |
| 43 | |
| 44 | template <typename TYPE> |
| 45 | TYPE parseKindSingleton(mlir::AsmParser &parser) { |
| 46 | return parseIntSingleton<TYPE>(parser); |
| 47 | } |
| 48 | |
| 49 | template <typename TYPE> |
| 50 | TYPE parseRankSingleton(mlir::AsmParser &parser) { |
| 51 | return parseIntSingleton<TYPE>(parser); |
| 52 | } |
| 53 | |
| 54 | template <typename TYPE> |
| 55 | TYPE parseTypeSingleton(mlir::AsmParser &parser) { |
| 56 | mlir::Type ty; |
| 57 | if (parser.parseLess() || parser.parseType(result&: ty) || parser.parseGreater()) |
| 58 | return {}; |
| 59 | return TYPE::get(ty); |
| 60 | } |
| 61 | |
| 62 | /// Is `ty` a standard or FIR integer type? |
| 63 | static bool isaIntegerType(mlir::Type ty) { |
| 64 | // TODO: why aren't we using isa_integer? investigatation required. |
| 65 | return mlir::isa<mlir::IntegerType, fir::IntegerType>(ty); |
| 66 | } |
| 67 | |
| 68 | bool verifyRecordMemberType(mlir::Type ty) { |
| 69 | return !mlir::isa<BoxCharType, ShapeType, ShapeShiftType, ShiftType, |
| 70 | SliceType, FieldType, LenType, ReferenceType, TypeDescType>( |
| 71 | ty); |
| 72 | } |
| 73 | |
| 74 | bool verifySameLists(llvm::ArrayRef<RecordType::TypePair> a1, |
| 75 | llvm::ArrayRef<RecordType::TypePair> a2) { |
| 76 | // FIXME: do we need to allow for any variance here? |
| 77 | return a1 == a2; |
| 78 | } |
| 79 | |
| 80 | static llvm::StringRef getVolatileKeyword() { return "volatile" ; } |
| 81 | |
| 82 | static mlir::ParseResult parseOptionalCommaAndKeyword(mlir::AsmParser &parser, |
| 83 | mlir::StringRef keyword, |
| 84 | bool &parsedKeyword) { |
| 85 | if (!parser.parseOptionalComma()) { |
| 86 | if (parser.parseKeyword(keyword)) |
| 87 | return mlir::failure(); |
| 88 | parsedKeyword = true; |
| 89 | return mlir::success(); |
| 90 | } |
| 91 | parsedKeyword = false; |
| 92 | return mlir::success(); |
| 93 | } |
| 94 | |
| 95 | RecordType verifyDerived(mlir::AsmParser &parser, RecordType derivedTy, |
| 96 | llvm::ArrayRef<RecordType::TypePair> lenPList, |
| 97 | llvm::ArrayRef<RecordType::TypePair> typeList) { |
| 98 | auto loc = parser.getNameLoc(); |
| 99 | if (!verifySameLists(derivedTy.getLenParamList(), lenPList) || |
| 100 | !verifySameLists(derivedTy.getTypeList(), typeList)) { |
| 101 | parser.emitError(loc, message: "cannot redefine record type members" ); |
| 102 | return {}; |
| 103 | } |
| 104 | for (auto &p : lenPList) |
| 105 | if (!isaIntegerType(p.second)) { |
| 106 | parser.emitError(loc, "LEN parameter must be integral type" ); |
| 107 | return {}; |
| 108 | } |
| 109 | for (auto &p : typeList) |
| 110 | if (!verifyRecordMemberType(p.second)) { |
| 111 | parser.emitError(loc, "field parameter has invalid type" ); |
| 112 | return {}; |
| 113 | } |
| 114 | llvm::StringSet<> uniq; |
| 115 | for (auto &p : lenPList) |
| 116 | if (!uniq.insert(p.first).second) { |
| 117 | parser.emitError(loc, "LEN parameter cannot have duplicate name" ); |
| 118 | return {}; |
| 119 | } |
| 120 | for (auto &p : typeList) |
| 121 | if (!uniq.insert(p.first).second) { |
| 122 | parser.emitError(loc, "field cannot have duplicate name" ); |
| 123 | return {}; |
| 124 | } |
| 125 | return derivedTy; |
| 126 | } |
| 127 | |
| 128 | } // namespace |
| 129 | |
| 130 | // Implementation of the thin interface from dialect to type parser |
| 131 | |
| 132 | mlir::Type fir::parseFirType(FIROpsDialect *dialect, |
| 133 | mlir::DialectAsmParser &parser) { |
| 134 | mlir::StringRef typeTag; |
| 135 | mlir::Type genType; |
| 136 | auto parseResult = generatedTypeParser(parser, &typeTag, genType); |
| 137 | if (parseResult.has_value()) |
| 138 | return genType; |
| 139 | parser.emitError(parser.getNameLoc(), "unknown fir type: " ) << typeTag; |
| 140 | return {}; |
| 141 | } |
| 142 | |
| 143 | namespace fir { |
| 144 | namespace detail { |
| 145 | |
| 146 | // Type storage classes |
| 147 | |
| 148 | /// Derived type storage |
| 149 | struct RecordTypeStorage : public mlir::TypeStorage { |
| 150 | using KeyTy = llvm::StringRef; |
| 151 | |
| 152 | static unsigned hashKey(const KeyTy &key) { |
| 153 | return llvm::hash_combine(args: key.str()); |
| 154 | } |
| 155 | |
| 156 | bool operator==(const KeyTy &key) const { return key == getName(); } |
| 157 | |
| 158 | static RecordTypeStorage *construct(mlir::TypeStorageAllocator &allocator, |
| 159 | const KeyTy &key) { |
| 160 | auto *storage = allocator.allocate<RecordTypeStorage>(); |
| 161 | return new (storage) RecordTypeStorage{key}; |
| 162 | } |
| 163 | |
| 164 | llvm::StringRef getName() const { return name; } |
| 165 | |
| 166 | void setLenParamList(llvm::ArrayRef<RecordType::TypePair> list) { |
| 167 | lens = list; |
| 168 | } |
| 169 | llvm::ArrayRef<RecordType::TypePair> getLenParamList() const { return lens; } |
| 170 | |
| 171 | void setTypeList(llvm::ArrayRef<RecordType::TypePair> list) { types = list; } |
| 172 | llvm::ArrayRef<RecordType::TypePair> getTypeList() const { return types; } |
| 173 | |
| 174 | bool isFinalized() const { return finalized; } |
| 175 | void finalize(llvm::ArrayRef<RecordType::TypePair> lenParamList, |
| 176 | llvm::ArrayRef<RecordType::TypePair> typeList) { |
| 177 | if (finalized) |
| 178 | return; |
| 179 | finalized = true; |
| 180 | setLenParamList(lenParamList); |
| 181 | setTypeList(typeList); |
| 182 | } |
| 183 | |
| 184 | bool isPacked() const { return packed; } |
| 185 | void pack(bool p) { packed = p; } |
| 186 | |
| 187 | protected: |
| 188 | std::string name; |
| 189 | bool finalized; |
| 190 | bool packed; |
| 191 | std::vector<RecordType::TypePair> lens; |
| 192 | std::vector<RecordType::TypePair> types; |
| 193 | |
| 194 | private: |
| 195 | RecordTypeStorage() = delete; |
| 196 | explicit RecordTypeStorage(llvm::StringRef name) |
| 197 | : name{name}, finalized{false}, packed{false} {} |
| 198 | }; |
| 199 | |
| 200 | } // namespace detail |
| 201 | |
| 202 | template <typename A, typename B> |
| 203 | bool inbounds(A v, B lb, B ub) { |
| 204 | return v >= lb && v < ub; |
| 205 | } |
| 206 | |
| 207 | bool isa_fir_type(mlir::Type t) { |
| 208 | return llvm::isa<FIROpsDialect>(t.getDialect()); |
| 209 | } |
| 210 | |
| 211 | bool isa_std_type(mlir::Type t) { |
| 212 | return llvm::isa<mlir::BuiltinDialect>(Val: t.getDialect()); |
| 213 | } |
| 214 | |
| 215 | bool isa_fir_or_std_type(mlir::Type t) { |
| 216 | if (auto funcType = mlir::dyn_cast<mlir::FunctionType>(t)) |
| 217 | return llvm::all_of(funcType.getInputs(), isa_fir_or_std_type) && |
| 218 | llvm::all_of(funcType.getResults(), isa_fir_or_std_type); |
| 219 | return isa_fir_type(t) || isa_std_type(t); |
| 220 | } |
| 221 | |
| 222 | mlir::Type getDerivedType(mlir::Type ty) { |
| 223 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(ty) |
| 224 | .Case<fir::PointerType, fir::HeapType, fir::SequenceType>([](auto p) { |
| 225 | if (auto seq = mlir::dyn_cast<fir::SequenceType>(p.getEleTy())) |
| 226 | return seq.getEleTy(); |
| 227 | return p.getEleTy(); |
| 228 | }) |
| 229 | .Case<fir::BaseBoxType>( |
| 230 | [](auto p) { return getDerivedType(p.getEleTy()); }) |
| 231 | .Default([](mlir::Type t) { return t; }); |
| 232 | } |
| 233 | |
| 234 | mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile) { |
| 235 | // If we already have the volatility we asked for, return the type unchanged. |
| 236 | if (fir::isa_volatile_type(type) == isVolatile) |
| 237 | return type; |
| 238 | return mlir::TypeSwitch<mlir::Type, mlir::Type>(type) |
| 239 | .Case<fir::BoxType, fir::ClassType, fir::ReferenceType>( |
| 240 | [&](auto ty) -> mlir::Type { |
| 241 | using TYPE = decltype(ty); |
| 242 | return TYPE::get(ty.getEleTy(), isVolatile); |
| 243 | }) |
| 244 | .Default([&](mlir::Type t) -> mlir::Type { return t; }); |
| 245 | } |
| 246 | |
| 247 | mlir::Type dyn_cast_ptrEleTy(mlir::Type t) { |
| 248 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(t) |
| 249 | .Case<fir::ReferenceType, fir::PointerType, fir::HeapType, |
| 250 | fir::LLVMPointerType>([](auto p) { return p.getEleTy(); }) |
| 251 | .Default([](mlir::Type) { return mlir::Type{}; }); |
| 252 | } |
| 253 | |
| 254 | mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t) { |
| 255 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(t) |
| 256 | .Case<fir::ReferenceType, fir::PointerType, fir::HeapType, |
| 257 | fir::LLVMPointerType>([](auto p) { return p.getEleTy(); }) |
| 258 | .Case<fir::BaseBoxType, fir::BoxCharType>( |
| 259 | [](auto p) { return unwrapRefType(p.getEleTy()); }) |
| 260 | .Default([](mlir::Type) { return mlir::Type{}; }); |
| 261 | } |
| 262 | |
| 263 | static bool hasDynamicSize(fir::RecordType recTy) { |
| 264 | for (auto field : recTy.getTypeList()) { |
| 265 | if (auto arr = mlir::dyn_cast<fir::SequenceType>(field.second)) { |
| 266 | if (sequenceWithNonConstantShape(arr)) |
| 267 | return true; |
| 268 | } else if (characterWithDynamicLen(field.second)) { |
| 269 | return true; |
| 270 | } else if (auto rec = mlir::dyn_cast<fir::RecordType>(field.second)) { |
| 271 | if (hasDynamicSize(rec)) |
| 272 | return true; |
| 273 | } |
| 274 | } |
| 275 | return false; |
| 276 | } |
| 277 | |
| 278 | bool hasDynamicSize(mlir::Type t) { |
| 279 | if (auto arr = mlir::dyn_cast<fir::SequenceType>(t)) { |
| 280 | if (sequenceWithNonConstantShape(arr)) |
| 281 | return true; |
| 282 | t = arr.getEleTy(); |
| 283 | } |
| 284 | if (characterWithDynamicLen(t)) |
| 285 | return true; |
| 286 | if (auto rec = mlir::dyn_cast<fir::RecordType>(t)) |
| 287 | return hasDynamicSize(rec); |
| 288 | return false; |
| 289 | } |
| 290 | |
| 291 | mlir::Type (mlir::Type ty) { |
| 292 | if (mlir::isa<fir::SequenceType>(ty)) |
| 293 | return ty; |
| 294 | if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) |
| 295 | return extractSequenceType(boxTy.getEleTy()); |
| 296 | if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty)) |
| 297 | return extractSequenceType(heapTy.getEleTy()); |
| 298 | if (auto ptrTy = mlir::dyn_cast<fir::PointerType>(ty)) |
| 299 | return extractSequenceType(ptrTy.getEleTy()); |
| 300 | return mlir::Type{}; |
| 301 | } |
| 302 | |
| 303 | bool isPointerType(mlir::Type ty) { |
| 304 | if (auto refTy = fir::dyn_cast_ptrEleTy(t: ty)) |
| 305 | ty = refTy; |
| 306 | if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) |
| 307 | return mlir::isa<fir::PointerType>(boxTy.getEleTy()); |
| 308 | return false; |
| 309 | } |
| 310 | |
| 311 | bool isAllocatableType(mlir::Type ty) { |
| 312 | if (auto refTy = fir::dyn_cast_ptrEleTy(t: ty)) |
| 313 | ty = refTy; |
| 314 | if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) |
| 315 | return mlir::isa<fir::HeapType>(boxTy.getEleTy()); |
| 316 | return false; |
| 317 | } |
| 318 | |
| 319 | bool isBoxNone(mlir::Type ty) { |
| 320 | if (auto box = mlir::dyn_cast<fir::BoxType>(ty)) |
| 321 | return mlir::isa<mlir::NoneType>(box.getEleTy()); |
| 322 | return false; |
| 323 | } |
| 324 | |
| 325 | bool isBoxedRecordType(mlir::Type ty) { |
| 326 | if (auto refTy = fir::dyn_cast_ptrEleTy(t: ty)) |
| 327 | ty = refTy; |
| 328 | if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) { |
| 329 | if (mlir::isa<fir::RecordType>(boxTy.getEleTy())) |
| 330 | return true; |
| 331 | mlir::Type innerType = boxTy.unwrapInnerType(); |
| 332 | return innerType && mlir::isa<fir::RecordType>(innerType); |
| 333 | } |
| 334 | return false; |
| 335 | } |
| 336 | |
| 337 | bool isScalarBoxedRecordType(mlir::Type ty) { |
| 338 | if (auto refTy = fir::dyn_cast_ptrEleTy(t: ty)) |
| 339 | ty = refTy; |
| 340 | if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) { |
| 341 | if (mlir::isa<fir::RecordType>(boxTy.getEleTy())) |
| 342 | return true; |
| 343 | if (auto heapTy = mlir::dyn_cast<fir::HeapType>(boxTy.getEleTy())) |
| 344 | return mlir::isa<fir::RecordType>(heapTy.getEleTy()); |
| 345 | if (auto ptrTy = mlir::dyn_cast<fir::PointerType>(boxTy.getEleTy())) |
| 346 | return mlir::isa<fir::RecordType>(ptrTy.getEleTy()); |
| 347 | } |
| 348 | return false; |
| 349 | } |
| 350 | |
| 351 | bool isAssumedType(mlir::Type ty) { |
| 352 | // Rule out CLASS(*) which are `fir.class<[fir.array] none>`. |
| 353 | if (mlir::isa<fir::ClassType>(ty)) |
| 354 | return false; |
| 355 | mlir::Type valueType = fir::unwrapPassByRefType(fir::unwrapRefType(ty)); |
| 356 | // Refuse raw `none` or `fir.array<none>` since assumed type |
| 357 | // should be in memory variables. |
| 358 | if (valueType == ty) |
| 359 | return false; |
| 360 | mlir::Type inner = fir::unwrapSequenceType(valueType); |
| 361 | return mlir::isa<mlir::NoneType>(Val: inner); |
| 362 | } |
| 363 | |
| 364 | bool isAssumedShape(mlir::Type ty) { |
| 365 | if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) |
| 366 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(boxTy.getEleTy())) |
| 367 | return seqTy.hasDynamicExtents(); |
| 368 | return false; |
| 369 | } |
| 370 | |
| 371 | bool isAllocatableOrPointerArray(mlir::Type ty) { |
| 372 | if (auto refTy = fir::dyn_cast_ptrEleTy(t: ty)) |
| 373 | ty = refTy; |
| 374 | if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) { |
| 375 | if (auto heapTy = mlir::dyn_cast<fir::HeapType>(boxTy.getEleTy())) |
| 376 | return mlir::isa<fir::SequenceType>(heapTy.getEleTy()); |
| 377 | if (auto ptrTy = mlir::dyn_cast<fir::PointerType>(boxTy.getEleTy())) |
| 378 | return mlir::isa<fir::SequenceType>(ptrTy.getEleTy()); |
| 379 | } |
| 380 | return false; |
| 381 | } |
| 382 | |
| 383 | bool isTypeWithDescriptor(mlir::Type ty) { |
| 384 | if (mlir::isa<fir::BaseBoxType>(unwrapRefType(ty))) |
| 385 | return true; |
| 386 | return false; |
| 387 | } |
| 388 | |
| 389 | bool isPolymorphicType(mlir::Type ty) { |
| 390 | // CLASS(T) or CLASS(*) |
| 391 | if (mlir::isa<fir::ClassType>(fir::unwrapRefType(ty))) |
| 392 | return true; |
| 393 | // assumed type are polymorphic. |
| 394 | return isAssumedType(ty); |
| 395 | } |
| 396 | |
| 397 | bool isUnlimitedPolymorphicType(mlir::Type ty) { |
| 398 | // CLASS(*) |
| 399 | if (auto clTy = mlir::dyn_cast<fir::ClassType>(fir::unwrapRefType(ty))) { |
| 400 | if (mlir::isa<mlir::NoneType>(clTy.getEleTy())) |
| 401 | return true; |
| 402 | mlir::Type innerType = clTy.unwrapInnerType(); |
| 403 | return innerType && mlir::isa<mlir::NoneType>(Val: innerType); |
| 404 | } |
| 405 | // TYPE(*) |
| 406 | return isAssumedType(ty); |
| 407 | } |
| 408 | |
| 409 | mlir::Type unwrapInnerType(mlir::Type ty) { |
| 410 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(ty) |
| 411 | .Case<fir::PointerType, fir::HeapType, fir::SequenceType>([](auto t) { |
| 412 | mlir::Type eleTy = t.getEleTy(); |
| 413 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) |
| 414 | return seqTy.getEleTy(); |
| 415 | return eleTy; |
| 416 | }) |
| 417 | .Case<fir::RecordType>([](auto t) { return t; }) |
| 418 | .Default([](mlir::Type) { return mlir::Type{}; }); |
| 419 | } |
| 420 | |
| 421 | bool isRecordWithAllocatableMember(mlir::Type ty) { |
| 422 | if (auto recTy = mlir::dyn_cast<fir::RecordType>(ty)) |
| 423 | for (auto [field, memTy] : recTy.getTypeList()) { |
| 424 | if (fir::isAllocatableType(memTy)) |
| 425 | return true; |
| 426 | // A record type cannot recursively include itself as a direct member. |
| 427 | // There must be an intervening `ptr` type, so recursion is safe here. |
| 428 | if (mlir::isa<fir::RecordType>(memTy) && |
| 429 | isRecordWithAllocatableMember(memTy)) |
| 430 | return true; |
| 431 | } |
| 432 | return false; |
| 433 | } |
| 434 | |
| 435 | bool isRecordWithDescriptorMember(mlir::Type ty) { |
| 436 | ty = unwrapSequenceType(ty); |
| 437 | if (auto recTy = mlir::dyn_cast<fir::RecordType>(ty)) |
| 438 | for (auto [field, memTy] : recTy.getTypeList()) { |
| 439 | memTy = unwrapSequenceType(memTy); |
| 440 | if (mlir::isa<fir::BaseBoxType>(memTy)) |
| 441 | return true; |
| 442 | if (mlir::isa<fir::RecordType>(memTy) && |
| 443 | isRecordWithDescriptorMember(memTy)) |
| 444 | return true; |
| 445 | } |
| 446 | return false; |
| 447 | } |
| 448 | |
| 449 | mlir::Type unwrapAllRefAndSeqType(mlir::Type ty) { |
| 450 | while (true) { |
| 451 | mlir::Type nt = unwrapSequenceType(unwrapRefType(ty)); |
| 452 | if (auto vecTy = mlir::dyn_cast<fir::VectorType>(nt)) |
| 453 | nt = vecTy.getEleTy(); |
| 454 | if (nt == ty) |
| 455 | return ty; |
| 456 | ty = nt; |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | mlir::Type getFortranElementType(mlir::Type ty) { |
| 461 | return fir::unwrapSequenceType( |
| 462 | fir::unwrapPassByRefType(fir::unwrapRefType(ty))); |
| 463 | } |
| 464 | |
| 465 | mlir::Type unwrapSeqOrBoxedSeqType(mlir::Type ty) { |
| 466 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) |
| 467 | return seqTy.getEleTy(); |
| 468 | if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(ty)) { |
| 469 | auto eleTy = unwrapRefType(boxTy.getEleTy()); |
| 470 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) |
| 471 | return seqTy.getEleTy(); |
| 472 | } |
| 473 | return ty; |
| 474 | } |
| 475 | |
| 476 | unsigned getBoxRank(mlir::Type boxTy) { |
| 477 | auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(t: boxTy); |
| 478 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) |
| 479 | return seqTy.getDimension(); |
| 480 | return 0; |
| 481 | } |
| 482 | |
| 483 | /// Return the ISO_C_BINDING intrinsic module value of type \p ty. |
| 484 | int getTypeCode(mlir::Type ty, const fir::KindMapping &kindMap) { |
| 485 | if (mlir::IntegerType intTy = mlir::dyn_cast<mlir::IntegerType>(ty)) { |
| 486 | if (intTy.isUnsigned()) { |
| 487 | switch (intTy.getWidth()) { |
| 488 | case 8: |
| 489 | return CFI_type_uint8_t; |
| 490 | case 16: |
| 491 | return CFI_type_uint16_t; |
| 492 | case 32: |
| 493 | return CFI_type_uint32_t; |
| 494 | case 64: |
| 495 | return CFI_type_uint64_t; |
| 496 | case 128: |
| 497 | return CFI_type_uint128_t; |
| 498 | } |
| 499 | llvm_unreachable("unsupported integer type" ); |
| 500 | } else { |
| 501 | switch (intTy.getWidth()) { |
| 502 | case 8: |
| 503 | return CFI_type_int8_t; |
| 504 | case 16: |
| 505 | return CFI_type_int16_t; |
| 506 | case 32: |
| 507 | return CFI_type_int32_t; |
| 508 | case 64: |
| 509 | return CFI_type_int64_t; |
| 510 | case 128: |
| 511 | return CFI_type_int128_t; |
| 512 | } |
| 513 | llvm_unreachable("unsupported integer type" ); |
| 514 | } |
| 515 | } |
| 516 | if (fir::LogicalType logicalTy = mlir::dyn_cast<fir::LogicalType>(ty)) { |
| 517 | switch (kindMap.getLogicalBitsize(logicalTy.getFKind())) { |
| 518 | case 8: |
| 519 | return CFI_type_Bool; |
| 520 | case 16: |
| 521 | return CFI_type_int_least16_t; |
| 522 | case 32: |
| 523 | return CFI_type_int_least32_t; |
| 524 | case 64: |
| 525 | return CFI_type_int_least64_t; |
| 526 | } |
| 527 | llvm_unreachable("unsupported logical type" ); |
| 528 | } |
| 529 | if (mlir::FloatType floatTy = mlir::dyn_cast<mlir::FloatType>(ty)) { |
| 530 | switch (floatTy.getWidth()) { |
| 531 | case 16: |
| 532 | return floatTy.isBF16() ? CFI_type_bfloat : CFI_type_half_float; |
| 533 | case 32: |
| 534 | return CFI_type_float; |
| 535 | case 64: |
| 536 | return CFI_type_double; |
| 537 | case 80: |
| 538 | return CFI_type_extended_double; |
| 539 | case 128: |
| 540 | return CFI_type_float128; |
| 541 | } |
| 542 | llvm_unreachable("unsupported real type" ); |
| 543 | } |
| 544 | if (mlir::ComplexType complexTy = mlir::dyn_cast<mlir::ComplexType>(ty)) { |
| 545 | mlir::FloatType floatTy = |
| 546 | mlir::cast<mlir::FloatType>(complexTy.getElementType()); |
| 547 | if (floatTy.isBF16()) |
| 548 | return CFI_type_bfloat_Complex; |
| 549 | switch (floatTy.getWidth()) { |
| 550 | case 16: |
| 551 | return CFI_type_half_float_Complex; |
| 552 | case 32: |
| 553 | return CFI_type_float_Complex; |
| 554 | case 64: |
| 555 | return CFI_type_double_Complex; |
| 556 | case 80: |
| 557 | return CFI_type_extended_double_Complex; |
| 558 | case 128: |
| 559 | return CFI_type_float128_Complex; |
| 560 | } |
| 561 | llvm_unreachable("unsupported complex size" ); |
| 562 | } |
| 563 | if (fir::CharacterType charTy = mlir::dyn_cast<fir::CharacterType>(ty)) { |
| 564 | switch (kindMap.getCharacterBitsize(charTy.getFKind())) { |
| 565 | case 8: |
| 566 | return CFI_type_char; |
| 567 | case 16: |
| 568 | return CFI_type_char16_t; |
| 569 | case 32: |
| 570 | return CFI_type_char32_t; |
| 571 | } |
| 572 | llvm_unreachable("unsupported character type" ); |
| 573 | } |
| 574 | if (fir::isa_ref_type(ty)) |
| 575 | return CFI_type_cptr; |
| 576 | if (mlir::isa<fir::RecordType>(ty)) |
| 577 | return CFI_type_struct; |
| 578 | llvm_unreachable("unsupported type" ); |
| 579 | } |
| 580 | |
| 581 | std::string getTypeAsString(mlir::Type ty, const fir::KindMapping &kindMap, |
| 582 | llvm::StringRef prefix) { |
| 583 | std::string buf = prefix.str(); |
| 584 | llvm::raw_string_ostream name{buf}; |
| 585 | if (!prefix.empty()) |
| 586 | name << "_" ; |
| 587 | |
| 588 | std::function<void(mlir::Type)> appendTypeName = [&](mlir::Type ty) { |
| 589 | while (ty) { |
| 590 | if (fir::isa_trivial(ty)) { |
| 591 | if (mlir::isa<mlir::IndexType>(Val: ty)) { |
| 592 | name << "idx" ; |
| 593 | } else if (ty.isIntOrIndex()) { |
| 594 | name << 'i' << ty.getIntOrFloatBitWidth(); |
| 595 | } else if (mlir::isa<mlir::FloatType>(Val: ty)) { |
| 596 | name << 'f' << ty.getIntOrFloatBitWidth(); |
| 597 | } else if (auto cplxTy = |
| 598 | mlir::dyn_cast_or_null<mlir::ComplexType>(ty)) { |
| 599 | name << 'z'; |
| 600 | auto floatTy = mlir::cast<mlir::FloatType>(cplxTy.getElementType()); |
| 601 | name << floatTy.getWidth(); |
| 602 | } else if (auto logTy = mlir::dyn_cast_or_null<fir::LogicalType>(ty)) { |
| 603 | name << 'l' << kindMap.getLogicalBitsize(logTy.getFKind()); |
| 604 | } else { |
| 605 | llvm::report_fatal_error(reason: "unsupported type" ); |
| 606 | } |
| 607 | break; |
| 608 | } else if (mlir::isa<mlir::NoneType>(Val: ty)) { |
| 609 | name << "none" ; |
| 610 | break; |
| 611 | } else if (auto charTy = mlir::dyn_cast_or_null<fir::CharacterType>(ty)) { |
| 612 | name << 'c' << kindMap.getCharacterBitsize(charTy.getFKind()); |
| 613 | if (charTy.getLen() == fir::CharacterType::unknownLen()) |
| 614 | name << "xU" ; |
| 615 | else if (charTy.getLen() != fir::CharacterType::singleton()) |
| 616 | name << "x" << charTy.getLen(); |
| 617 | break; |
| 618 | } else if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(ty)) { |
| 619 | for (auto extent : seqTy.getShape()) { |
| 620 | if (extent == fir::SequenceType::getUnknownExtent()) |
| 621 | name << "Ux" ; |
| 622 | else |
| 623 | name << extent << 'x'; |
| 624 | } |
| 625 | ty = seqTy.getEleTy(); |
| 626 | } else if (auto refTy = mlir::dyn_cast_or_null<fir::ReferenceType>(ty)) { |
| 627 | name << "ref_" ; |
| 628 | ty = refTy.getEleTy(); |
| 629 | } else if (auto ptrTy = mlir::dyn_cast_or_null<fir::PointerType>(ty)) { |
| 630 | name << "ptr_" ; |
| 631 | ty = ptrTy.getEleTy(); |
| 632 | } else if (auto ptrTy = |
| 633 | mlir::dyn_cast_or_null<fir::LLVMPointerType>(ty)) { |
| 634 | name << "llvmptr_" ; |
| 635 | ty = ptrTy.getEleTy(); |
| 636 | } else if (auto heapTy = mlir::dyn_cast_or_null<fir::HeapType>(ty)) { |
| 637 | name << "heap_" ; |
| 638 | ty = heapTy.getEleTy(); |
| 639 | } else if (auto classTy = mlir::dyn_cast_or_null<fir::ClassType>(ty)) { |
| 640 | name << "class_" ; |
| 641 | ty = classTy.getEleTy(); |
| 642 | } else if (auto boxTy = mlir::dyn_cast_or_null<fir::BoxType>(ty)) { |
| 643 | name << "box_" ; |
| 644 | ty = boxTy.getEleTy(); |
| 645 | } else if (auto boxcharTy = |
| 646 | mlir::dyn_cast_or_null<fir::BoxCharType>(ty)) { |
| 647 | name << "boxchar_" ; |
| 648 | ty = boxcharTy.getEleTy(); |
| 649 | } else if (auto boxprocTy = |
| 650 | mlir::dyn_cast_or_null<fir::BoxProcType>(ty)) { |
| 651 | name << "boxproc_" ; |
| 652 | auto procTy = mlir::dyn_cast<mlir::FunctionType>(boxprocTy.getEleTy()); |
| 653 | assert(procTy.getNumResults() <= 1 && |
| 654 | "function type with more than one result" ); |
| 655 | for (const auto &result : procTy.getResults()) |
| 656 | appendTypeName(result); |
| 657 | name << "_args" ; |
| 658 | for (const auto &arg : procTy.getInputs()) { |
| 659 | name << '_'; |
| 660 | appendTypeName(arg); |
| 661 | } |
| 662 | break; |
| 663 | } else if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(ty)) { |
| 664 | name << "rec_" << recTy.getName(); |
| 665 | break; |
| 666 | } else { |
| 667 | llvm::report_fatal_error(reason: "unsupported type" ); |
| 668 | } |
| 669 | } |
| 670 | }; |
| 671 | |
| 672 | appendTypeName(ty); |
| 673 | return buf; |
| 674 | } |
| 675 | |
| 676 | mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType, |
| 677 | bool turnBoxIntoClass) { |
| 678 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(type) |
| 679 | .Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type { |
| 680 | return fir::SequenceType::get(seqTy.getShape(), newElementType); |
| 681 | }) |
| 682 | .Case<fir::ReferenceType, fir::ClassType>([&](auto t) -> mlir::Type { |
| 683 | using FIRT = decltype(t); |
| 684 | auto newEleTy = |
| 685 | changeElementType(t.getEleTy(), newElementType, turnBoxIntoClass); |
| 686 | return FIRT::get(newEleTy, t.isVolatile()); |
| 687 | }) |
| 688 | .Case<fir::PointerType, fir::HeapType>([&](auto t) -> mlir::Type { |
| 689 | using FIRT = decltype(t); |
| 690 | return FIRT::get( |
| 691 | changeElementType(t.getEleTy(), newElementType, turnBoxIntoClass)); |
| 692 | }) |
| 693 | .Case<fir::BoxType>([&](fir::BoxType t) -> mlir::Type { |
| 694 | mlir::Type newInnerType = |
| 695 | changeElementType(t.getEleTy(), newElementType, false); |
| 696 | if (turnBoxIntoClass) |
| 697 | return fir::ClassType::get(newInnerType, t.isVolatile()); |
| 698 | return fir::BoxType::get(newInnerType, t.isVolatile()); |
| 699 | }) |
| 700 | .Default([&](mlir::Type t) -> mlir::Type { |
| 701 | assert((fir::isa_trivial(t) || llvm::isa<fir::RecordType>(t) || |
| 702 | llvm::isa<mlir::NoneType>(t)) && |
| 703 | "unexpected FIR leaf type" ); |
| 704 | return newElementType; |
| 705 | }); |
| 706 | } |
| 707 | |
| 708 | } // namespace fir |
| 709 | |
| 710 | namespace { |
| 711 | |
| 712 | static llvm::SmallPtrSet<detail::RecordTypeStorage const *, 4> |
| 713 | recordTypeVisited; |
| 714 | |
| 715 | } // namespace |
| 716 | |
| 717 | void fir::verifyIntegralType(mlir::Type type) { |
| 718 | if (isaIntegerType(ty: type) || mlir::isa<mlir::IndexType>(Val: type)) |
| 719 | return; |
| 720 | llvm::report_fatal_error(reason: "expected integral type" ); |
| 721 | } |
| 722 | |
| 723 | void fir::printFirType(FIROpsDialect *, mlir::Type ty, |
| 724 | mlir::DialectAsmPrinter &p) { |
| 725 | if (mlir::failed(Result: generatedTypePrinter(ty, p))) |
| 726 | llvm::report_fatal_error(reason: "unknown type to print" ); |
| 727 | } |
| 728 | |
| 729 | bool fir::isa_unknown_size_box(mlir::Type t) { |
| 730 | if (auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(t)) { |
| 731 | auto valueType = fir::unwrapPassByRefType(boxTy); |
| 732 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(valueType)) |
| 733 | if (seqTy.hasUnknownShape()) |
| 734 | return true; |
| 735 | } |
| 736 | return false; |
| 737 | } |
| 738 | |
| 739 | bool fir::isa_volatile_type(mlir::Type t) { |
| 740 | return llvm::TypeSwitch<mlir::Type, bool>(t) |
| 741 | .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>( |
| 742 | [](auto t) { return t.isVolatile(); }) |
| 743 | .Default([](mlir::Type) { return false; }); |
| 744 | } |
| 745 | |
| 746 | //===----------------------------------------------------------------------===// |
| 747 | // BoxProcType |
| 748 | //===----------------------------------------------------------------------===// |
| 749 | |
| 750 | // `boxproc` `<` return-type `>` |
| 751 | mlir::Type BoxProcType::parse(mlir::AsmParser &parser) { |
| 752 | mlir::Type ty; |
| 753 | if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) |
| 754 | return {}; |
| 755 | return get(parser.getContext(), ty); |
| 756 | } |
| 757 | |
| 758 | void fir::BoxProcType::print(mlir::AsmPrinter &printer) const { |
| 759 | printer << "<" << getEleTy() << '>'; |
| 760 | } |
| 761 | |
| 762 | llvm::LogicalResult |
| 763 | BoxProcType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 764 | mlir::Type eleTy) { |
| 765 | if (mlir::isa<mlir::FunctionType>(eleTy)) |
| 766 | return mlir::success(); |
| 767 | if (auto refTy = mlir::dyn_cast<ReferenceType>(eleTy)) |
| 768 | if (mlir::isa<mlir::FunctionType>(refTy)) |
| 769 | return mlir::success(); |
| 770 | return emitError() << "invalid type for boxproc" << eleTy << '\n'; |
| 771 | } |
| 772 | |
| 773 | static bool cannotBePointerOrHeapElementType(mlir::Type eleTy) { |
| 774 | return mlir::isa<BoxType, BoxCharType, BoxProcType, ShapeType, ShapeShiftType, |
| 775 | SliceType, FieldType, LenType, HeapType, PointerType, |
| 776 | ReferenceType, TypeDescType>(eleTy); |
| 777 | } |
| 778 | |
| 779 | //===----------------------------------------------------------------------===// |
| 780 | // BoxType |
| 781 | //===----------------------------------------------------------------------===// |
| 782 | |
| 783 | // `box` `<` type (`, volatile` $volatile^)? `>` |
| 784 | mlir::Type fir::BoxType::parse(mlir::AsmParser &parser) { |
| 785 | mlir::Type eleTy; |
| 786 | auto location = parser.getCurrentLocation(); |
| 787 | auto *context = parser.getContext(); |
| 788 | bool isVolatile = false; |
| 789 | if (parser.parseLess() || parser.parseType(eleTy)) |
| 790 | return {}; |
| 791 | if (parseOptionalCommaAndKeyword(parser, getVolatileKeyword(), isVolatile)) |
| 792 | return {}; |
| 793 | if (parser.parseGreater()) |
| 794 | return {}; |
| 795 | return parser.getChecked<fir::BoxType>(location, context, eleTy, isVolatile); |
| 796 | } |
| 797 | |
| 798 | void fir::BoxType::print(mlir::AsmPrinter &printer) const { |
| 799 | printer << "<" << getEleTy(); |
| 800 | if (isVolatile()) |
| 801 | printer << ", " << getVolatileKeyword(); |
| 802 | printer << '>'; |
| 803 | } |
| 804 | |
| 805 | llvm::LogicalResult |
| 806 | fir::BoxType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 807 | mlir::Type eleTy, bool isVolatile) { |
| 808 | if (mlir::isa<fir::BaseBoxType>(eleTy)) |
| 809 | return emitError() << "invalid element type\n" ; |
| 810 | // TODO |
| 811 | return mlir::success(); |
| 812 | } |
| 813 | |
| 814 | //===----------------------------------------------------------------------===// |
| 815 | // BoxCharType |
| 816 | //===----------------------------------------------------------------------===// |
| 817 | |
| 818 | mlir::Type fir::BoxCharType::parse(mlir::AsmParser &parser) { |
| 819 | return parseKindSingleton<fir::BoxCharType>(parser); |
| 820 | } |
| 821 | |
| 822 | void fir::BoxCharType::print(mlir::AsmPrinter &printer) const { |
| 823 | printer << "<" << getKind() << ">" ; |
| 824 | } |
| 825 | |
| 826 | CharacterType |
| 827 | fir::BoxCharType::getElementType(mlir::MLIRContext *context) const { |
| 828 | return CharacterType::getUnknownLen(context, getKind()); |
| 829 | } |
| 830 | |
| 831 | CharacterType fir::BoxCharType::getEleTy() const { |
| 832 | return getElementType(getContext()); |
| 833 | } |
| 834 | |
| 835 | //===----------------------------------------------------------------------===// |
| 836 | // CharacterType |
| 837 | //===----------------------------------------------------------------------===// |
| 838 | |
| 839 | // `char` `<` kind [`,` `len`] `>` |
| 840 | mlir::Type fir::CharacterType::parse(mlir::AsmParser &parser) { |
| 841 | int kind = 0; |
| 842 | if (parser.parseLess() || parser.parseInteger(kind)) |
| 843 | return {}; |
| 844 | CharacterType::LenType len = 1; |
| 845 | if (mlir::succeeded(parser.parseOptionalComma())) { |
| 846 | if (mlir::succeeded(parser.parseOptionalQuestion())) { |
| 847 | len = fir::CharacterType::unknownLen(); |
| 848 | } else if (!mlir::succeeded(parser.parseInteger(len))) { |
| 849 | return {}; |
| 850 | } |
| 851 | } |
| 852 | if (parser.parseGreater()) |
| 853 | return {}; |
| 854 | return get(parser.getContext(), kind, len); |
| 855 | } |
| 856 | |
| 857 | void fir::CharacterType::print(mlir::AsmPrinter &printer) const { |
| 858 | printer << "<" << getFKind(); |
| 859 | auto len = getLen(); |
| 860 | if (len != fir::CharacterType::singleton()) { |
| 861 | printer << ','; |
| 862 | if (len == fir::CharacterType::unknownLen()) |
| 863 | printer << '?'; |
| 864 | else |
| 865 | printer << len; |
| 866 | } |
| 867 | printer << '>'; |
| 868 | } |
| 869 | |
| 870 | //===----------------------------------------------------------------------===// |
| 871 | // ClassType |
| 872 | //===----------------------------------------------------------------------===// |
| 873 | |
| 874 | // `class` `<` type (`, volatile` $volatile^)? `>` |
| 875 | mlir::Type fir::ClassType::parse(mlir::AsmParser &parser) { |
| 876 | mlir::Type eleTy; |
| 877 | auto location = parser.getCurrentLocation(); |
| 878 | auto *context = parser.getContext(); |
| 879 | bool isVolatile = false; |
| 880 | if (parser.parseLess() || parser.parseType(eleTy)) |
| 881 | return {}; |
| 882 | if (parseOptionalCommaAndKeyword(parser, getVolatileKeyword(), isVolatile)) |
| 883 | return {}; |
| 884 | if (parser.parseGreater()) |
| 885 | return {}; |
| 886 | return parser.getChecked<fir::ClassType>(location, context, eleTy, |
| 887 | isVolatile); |
| 888 | } |
| 889 | |
| 890 | void fir::ClassType::print(mlir::AsmPrinter &printer) const { |
| 891 | printer << "<" << getEleTy(); |
| 892 | if (isVolatile()) |
| 893 | printer << ", " << getVolatileKeyword(); |
| 894 | printer << '>'; |
| 895 | } |
| 896 | |
| 897 | llvm::LogicalResult |
| 898 | fir::ClassType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 899 | mlir::Type eleTy, bool isVolatile) { |
| 900 | if (mlir::isa<fir::RecordType, fir::SequenceType, fir::HeapType, |
| 901 | fir::PointerType, mlir::NoneType, mlir::IntegerType, |
| 902 | mlir::FloatType, fir::CharacterType, fir::LogicalType, |
| 903 | mlir::ComplexType>(eleTy)) |
| 904 | return mlir::success(); |
| 905 | return emitError() << "invalid element type\n" ; |
| 906 | } |
| 907 | |
| 908 | //===----------------------------------------------------------------------===// |
| 909 | // HeapType |
| 910 | //===----------------------------------------------------------------------===// |
| 911 | |
| 912 | // `heap` `<` type `>` |
| 913 | mlir::Type fir::HeapType::parse(mlir::AsmParser &parser) { |
| 914 | return parseTypeSingleton<HeapType>(parser); |
| 915 | } |
| 916 | |
| 917 | void fir::HeapType::print(mlir::AsmPrinter &printer) const { |
| 918 | printer << "<" << getEleTy() << '>'; |
| 919 | } |
| 920 | |
| 921 | llvm::LogicalResult |
| 922 | fir::HeapType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 923 | mlir::Type eleTy) { |
| 924 | if (cannotBePointerOrHeapElementType(eleTy)) |
| 925 | return emitError() << "cannot build a heap pointer to type: " << eleTy |
| 926 | << '\n'; |
| 927 | return mlir::success(); |
| 928 | } |
| 929 | |
| 930 | //===----------------------------------------------------------------------===// |
| 931 | // IntegerType |
| 932 | //===----------------------------------------------------------------------===// |
| 933 | |
| 934 | // `int` `<` kind `>` |
| 935 | mlir::Type fir::IntegerType::parse(mlir::AsmParser &parser) { |
| 936 | return parseKindSingleton<fir::IntegerType>(parser); |
| 937 | } |
| 938 | |
| 939 | void fir::IntegerType::print(mlir::AsmPrinter &printer) const { |
| 940 | printer << "<" << getFKind() << '>'; |
| 941 | } |
| 942 | |
| 943 | //===----------------------------------------------------------------------===// |
| 944 | // UnsignedType |
| 945 | //===----------------------------------------------------------------------===// |
| 946 | |
| 947 | // `unsigned` `<` kind `>` |
| 948 | mlir::Type fir::UnsignedType::parse(mlir::AsmParser &parser) { |
| 949 | return parseKindSingleton<fir::UnsignedType>(parser); |
| 950 | } |
| 951 | |
| 952 | void fir::UnsignedType::print(mlir::AsmPrinter &printer) const { |
| 953 | printer << "<" << getFKind() << '>'; |
| 954 | } |
| 955 | |
| 956 | //===----------------------------------------------------------------------===// |
| 957 | // LogicalType |
| 958 | //===----------------------------------------------------------------------===// |
| 959 | |
| 960 | // `logical` `<` kind `>` |
| 961 | mlir::Type fir::LogicalType::parse(mlir::AsmParser &parser) { |
| 962 | return parseKindSingleton<fir::LogicalType>(parser); |
| 963 | } |
| 964 | |
| 965 | void fir::LogicalType::print(mlir::AsmPrinter &printer) const { |
| 966 | printer << "<" << getFKind() << '>'; |
| 967 | } |
| 968 | |
| 969 | //===----------------------------------------------------------------------===// |
| 970 | // PointerType |
| 971 | //===----------------------------------------------------------------------===// |
| 972 | |
| 973 | // `ptr` `<` type `>` |
| 974 | mlir::Type fir::PointerType::parse(mlir::AsmParser &parser) { |
| 975 | return parseTypeSingleton<fir::PointerType>(parser); |
| 976 | } |
| 977 | |
| 978 | void fir::PointerType::print(mlir::AsmPrinter &printer) const { |
| 979 | printer << "<" << getEleTy() << '>'; |
| 980 | } |
| 981 | |
| 982 | llvm::LogicalResult fir::PointerType::verify( |
| 983 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 984 | mlir::Type eleTy) { |
| 985 | if (cannotBePointerOrHeapElementType(eleTy)) |
| 986 | return emitError() << "cannot build a pointer to type: " << eleTy << '\n'; |
| 987 | return mlir::success(); |
| 988 | } |
| 989 | |
| 990 | //===----------------------------------------------------------------------===// |
| 991 | // RecordType |
| 992 | //===----------------------------------------------------------------------===// |
| 993 | |
| 994 | // Fortran derived type |
| 995 | // unpacked: |
| 996 | // `type` `<` name |
| 997 | // (`(` id `:` type (`,` id `:` type)* `)`)? |
| 998 | // (`{` id `:` type (`,` id `:` type)* `}`)? '>' |
| 999 | // packed: |
| 1000 | // `type` `<` name |
| 1001 | // (`(` id `:` type (`,` id `:` type)* `)`)? |
| 1002 | // (`<{` id `:` type (`,` id `:` type)* `}>`)? '>' |
| 1003 | mlir::Type fir::RecordType::parse(mlir::AsmParser &parser) { |
| 1004 | llvm::StringRef name; |
| 1005 | if (parser.parseLess() || parser.parseKeyword(&name)) |
| 1006 | return {}; |
| 1007 | RecordType result = RecordType::get(parser.getContext(), name); |
| 1008 | |
| 1009 | RecordType::TypeList lenParamList; |
| 1010 | if (!parser.parseOptionalLParen()) { |
| 1011 | while (true) { |
| 1012 | llvm::StringRef lenparam; |
| 1013 | mlir::Type intTy; |
| 1014 | if (parser.parseKeyword(&lenparam) || parser.parseColon() || |
| 1015 | parser.parseType(intTy)) { |
| 1016 | parser.emitError(parser.getNameLoc(), "expected LEN parameter list" ); |
| 1017 | return {}; |
| 1018 | } |
| 1019 | lenParamList.emplace_back(lenparam, intTy); |
| 1020 | if (parser.parseOptionalComma()) |
| 1021 | break; |
| 1022 | } |
| 1023 | if (parser.parseRParen()) |
| 1024 | return {}; |
| 1025 | } |
| 1026 | |
| 1027 | RecordType::TypeList typeList; |
| 1028 | if (!parser.parseOptionalLess()) { |
| 1029 | result.pack(true); |
| 1030 | } |
| 1031 | |
| 1032 | if (!parser.parseOptionalLBrace()) { |
| 1033 | while (true) { |
| 1034 | llvm::StringRef field; |
| 1035 | mlir::Type fldTy; |
| 1036 | if (parser.parseKeyword(&field) || parser.parseColon() || |
| 1037 | parser.parseType(fldTy)) { |
| 1038 | parser.emitError(parser.getNameLoc(), "expected field type list" ); |
| 1039 | return {}; |
| 1040 | } |
| 1041 | typeList.emplace_back(field, fldTy); |
| 1042 | if (parser.parseOptionalComma()) |
| 1043 | break; |
| 1044 | } |
| 1045 | if (parser.parseOptionalGreater()) { |
| 1046 | if (parser.parseRBrace()) |
| 1047 | return {}; |
| 1048 | } |
| 1049 | } |
| 1050 | |
| 1051 | if (parser.parseGreater()) |
| 1052 | return {}; |
| 1053 | |
| 1054 | if (lenParamList.empty() && typeList.empty()) |
| 1055 | return result; |
| 1056 | |
| 1057 | result.finalize(lenParamList, typeList); |
| 1058 | return verifyDerived(parser, result, lenParamList, typeList); |
| 1059 | } |
| 1060 | |
| 1061 | void fir::RecordType::print(mlir::AsmPrinter &printer) const { |
| 1062 | printer << "<" << getName(); |
| 1063 | if (!recordTypeVisited.count(uniqueKey())) { |
| 1064 | recordTypeVisited.insert(uniqueKey()); |
| 1065 | if (getLenParamList().size()) { |
| 1066 | char ch = '('; |
| 1067 | for (auto p : getLenParamList()) { |
| 1068 | printer << ch << p.first << ':'; |
| 1069 | p.second.print(printer.getStream()); |
| 1070 | ch = ','; |
| 1071 | } |
| 1072 | printer << ')'; |
| 1073 | } |
| 1074 | if (getTypeList().size()) { |
| 1075 | if (isPacked()) { |
| 1076 | printer << '<'; |
| 1077 | } |
| 1078 | char ch = '{'; |
| 1079 | for (auto p : getTypeList()) { |
| 1080 | printer << ch << p.first << ':'; |
| 1081 | p.second.print(printer.getStream()); |
| 1082 | ch = ','; |
| 1083 | } |
| 1084 | printer << '}'; |
| 1085 | if (isPacked()) { |
| 1086 | printer << '>'; |
| 1087 | } |
| 1088 | } |
| 1089 | recordTypeVisited.erase(uniqueKey()); |
| 1090 | } |
| 1091 | printer << '>'; |
| 1092 | } |
| 1093 | |
| 1094 | void fir::RecordType::finalize(llvm::ArrayRef<TypePair> lenPList, |
| 1095 | llvm::ArrayRef<TypePair> typeList) { |
| 1096 | getImpl()->finalize(lenPList, typeList); |
| 1097 | } |
| 1098 | |
| 1099 | llvm::StringRef fir::RecordType::getName() const { |
| 1100 | return getImpl()->getName(); |
| 1101 | } |
| 1102 | |
| 1103 | RecordType::TypeList fir::RecordType::getTypeList() const { |
| 1104 | return getImpl()->getTypeList(); |
| 1105 | } |
| 1106 | |
| 1107 | RecordType::TypeList fir::RecordType::getLenParamList() const { |
| 1108 | return getImpl()->getLenParamList(); |
| 1109 | } |
| 1110 | |
| 1111 | bool fir::RecordType::isFinalized() const { return getImpl()->isFinalized(); } |
| 1112 | |
| 1113 | void fir::RecordType::pack(bool p) { getImpl()->pack(p); } |
| 1114 | |
| 1115 | bool fir::RecordType::isPacked() const { return getImpl()->isPacked(); } |
| 1116 | |
| 1117 | detail::RecordTypeStorage const *fir::RecordType::uniqueKey() const { |
| 1118 | return getImpl(); |
| 1119 | } |
| 1120 | |
| 1121 | llvm::LogicalResult fir::RecordType::verify( |
| 1122 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 1123 | llvm::StringRef name) { |
| 1124 | if (name.size() == 0) |
| 1125 | return emitError() << "record types must have a name" ; |
| 1126 | return mlir::success(); |
| 1127 | } |
| 1128 | |
| 1129 | mlir::Type fir::RecordType::getType(llvm::StringRef ident) { |
| 1130 | for (auto f : getTypeList()) |
| 1131 | if (ident == f.first) |
| 1132 | return f.second; |
| 1133 | return {}; |
| 1134 | } |
| 1135 | |
| 1136 | unsigned fir::RecordType::getFieldIndex(llvm::StringRef ident) { |
| 1137 | for (auto f : llvm::enumerate(getTypeList())) |
| 1138 | if (ident == f.value().first) |
| 1139 | return f.index(); |
| 1140 | return std::numeric_limits<unsigned>::max(); |
| 1141 | } |
| 1142 | |
| 1143 | //===----------------------------------------------------------------------===// |
| 1144 | // ReferenceType |
| 1145 | //===----------------------------------------------------------------------===// |
| 1146 | |
| 1147 | // `ref` `<` type (`, volatile` $volatile^)? `>` |
| 1148 | mlir::Type fir::ReferenceType::parse(mlir::AsmParser &parser) { |
| 1149 | auto location = parser.getCurrentLocation(); |
| 1150 | auto *context = parser.getContext(); |
| 1151 | mlir::Type eleTy; |
| 1152 | bool isVolatile = false; |
| 1153 | if (parser.parseLess() || parser.parseType(eleTy)) |
| 1154 | return {}; |
| 1155 | if (parseOptionalCommaAndKeyword(parser, getVolatileKeyword(), isVolatile)) |
| 1156 | return {}; |
| 1157 | if (parser.parseGreater()) |
| 1158 | return {}; |
| 1159 | return parser.getChecked<fir::ReferenceType>(location, context, eleTy, |
| 1160 | isVolatile); |
| 1161 | } |
| 1162 | |
| 1163 | void fir::ReferenceType::print(mlir::AsmPrinter &printer) const { |
| 1164 | printer << "<" << getEleTy(); |
| 1165 | if (isVolatile()) |
| 1166 | printer << ", " << getVolatileKeyword(); |
| 1167 | printer << '>'; |
| 1168 | } |
| 1169 | |
| 1170 | llvm::LogicalResult fir::ReferenceType::verify( |
| 1171 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, mlir::Type eleTy, |
| 1172 | bool isVolatile) { |
| 1173 | if (mlir::isa<ShapeType, ShapeShiftType, SliceType, FieldType, LenType, |
| 1174 | ReferenceType, TypeDescType>(eleTy)) |
| 1175 | return emitError() << "cannot build a reference to type: " << eleTy << '\n'; |
| 1176 | return mlir::success(); |
| 1177 | } |
| 1178 | |
| 1179 | //===----------------------------------------------------------------------===// |
| 1180 | // SequenceType |
| 1181 | //===----------------------------------------------------------------------===// |
| 1182 | |
| 1183 | // `array` `<` `*` | bounds (`x` bounds)* `:` type (',' affine-map)? `>` |
| 1184 | // bounds ::= `?` | int-lit |
| 1185 | mlir::Type fir::SequenceType::parse(mlir::AsmParser &parser) { |
| 1186 | if (parser.parseLess()) |
| 1187 | return {}; |
| 1188 | SequenceType::Shape shape; |
| 1189 | if (parser.parseOptionalStar()) { |
| 1190 | if (parser.parseDimensionList(shape, /*allowDynamic=*/true)) |
| 1191 | return {}; |
| 1192 | } else if (parser.parseColon()) { |
| 1193 | return {}; |
| 1194 | } |
| 1195 | mlir::Type eleTy; |
| 1196 | if (parser.parseType(eleTy)) |
| 1197 | return {}; |
| 1198 | mlir::AffineMapAttr map; |
| 1199 | if (!parser.parseOptionalComma()) { |
| 1200 | if (parser.parseAttribute(map)) { |
| 1201 | parser.emitError(parser.getNameLoc(), "expecting affine map" ); |
| 1202 | return {}; |
| 1203 | } |
| 1204 | } |
| 1205 | if (parser.parseGreater()) |
| 1206 | return {}; |
| 1207 | return SequenceType::get(parser.getContext(), shape, eleTy, map); |
| 1208 | } |
| 1209 | |
| 1210 | void fir::SequenceType::print(mlir::AsmPrinter &printer) const { |
| 1211 | auto shape = getShape(); |
| 1212 | if (shape.size()) { |
| 1213 | printer << '<'; |
| 1214 | for (const auto &b : shape) { |
| 1215 | if (b >= 0) |
| 1216 | printer << b << 'x'; |
| 1217 | else |
| 1218 | printer << "?x" ; |
| 1219 | } |
| 1220 | } else { |
| 1221 | printer << "<*:" ; |
| 1222 | } |
| 1223 | printer << getEleTy(); |
| 1224 | if (auto map = getLayoutMap()) { |
| 1225 | printer << ", " ; |
| 1226 | map.print(printer.getStream()); |
| 1227 | } |
| 1228 | printer << '>'; |
| 1229 | } |
| 1230 | |
| 1231 | unsigned fir::SequenceType::getConstantRows() const { |
| 1232 | if (hasDynamicSize(getEleTy())) |
| 1233 | return 0; |
| 1234 | auto shape = getShape(); |
| 1235 | unsigned count = 0; |
| 1236 | for (auto d : shape) { |
| 1237 | if (d == getUnknownExtent()) |
| 1238 | break; |
| 1239 | ++count; |
| 1240 | } |
| 1241 | return count; |
| 1242 | } |
| 1243 | |
| 1244 | llvm::LogicalResult fir::SequenceType::verify( |
| 1245 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 1246 | llvm::ArrayRef<int64_t> shape, mlir::Type eleTy, |
| 1247 | mlir::AffineMapAttr layoutMap) { |
| 1248 | // DIMENSION attribute can only be applied to an intrinsic or record type |
| 1249 | if (mlir::isa<BoxType, BoxCharType, BoxProcType, ShapeType, ShapeShiftType, |
| 1250 | ShiftType, SliceType, FieldType, LenType, HeapType, PointerType, |
| 1251 | ReferenceType, TypeDescType, SequenceType>(eleTy)) |
| 1252 | return emitError() << "cannot build an array of this element type: " |
| 1253 | << eleTy << '\n'; |
| 1254 | return mlir::success(); |
| 1255 | } |
| 1256 | |
| 1257 | //===----------------------------------------------------------------------===// |
| 1258 | // ShapeType |
| 1259 | //===----------------------------------------------------------------------===// |
| 1260 | |
| 1261 | mlir::Type fir::ShapeType::parse(mlir::AsmParser &parser) { |
| 1262 | return parseRankSingleton<fir::ShapeType>(parser); |
| 1263 | } |
| 1264 | |
| 1265 | void fir::ShapeType::print(mlir::AsmPrinter &printer) const { |
| 1266 | printer << "<" << getImpl()->rank << ">" ; |
| 1267 | } |
| 1268 | |
| 1269 | //===----------------------------------------------------------------------===// |
| 1270 | // ShapeShiftType |
| 1271 | //===----------------------------------------------------------------------===// |
| 1272 | |
| 1273 | mlir::Type fir::ShapeShiftType::parse(mlir::AsmParser &parser) { |
| 1274 | return parseRankSingleton<fir::ShapeShiftType>(parser); |
| 1275 | } |
| 1276 | |
| 1277 | void fir::ShapeShiftType::print(mlir::AsmPrinter &printer) const { |
| 1278 | printer << "<" << getRank() << ">" ; |
| 1279 | } |
| 1280 | |
| 1281 | //===----------------------------------------------------------------------===// |
| 1282 | // ShiftType |
| 1283 | //===----------------------------------------------------------------------===// |
| 1284 | |
| 1285 | mlir::Type fir::ShiftType::parse(mlir::AsmParser &parser) { |
| 1286 | return parseRankSingleton<fir::ShiftType>(parser); |
| 1287 | } |
| 1288 | |
| 1289 | void fir::ShiftType::print(mlir::AsmPrinter &printer) const { |
| 1290 | printer << "<" << getRank() << ">" ; |
| 1291 | } |
| 1292 | |
| 1293 | //===----------------------------------------------------------------------===// |
| 1294 | // SliceType |
| 1295 | //===----------------------------------------------------------------------===// |
| 1296 | |
| 1297 | // `slice` `<` rank `>` |
| 1298 | mlir::Type fir::SliceType::parse(mlir::AsmParser &parser) { |
| 1299 | return parseRankSingleton<fir::SliceType>(parser); |
| 1300 | } |
| 1301 | |
| 1302 | void fir::SliceType::print(mlir::AsmPrinter &printer) const { |
| 1303 | printer << "<" << getRank() << '>'; |
| 1304 | } |
| 1305 | |
| 1306 | //===----------------------------------------------------------------------===// |
| 1307 | // TypeDescType |
| 1308 | //===----------------------------------------------------------------------===// |
| 1309 | |
| 1310 | // `tdesc` `<` type `>` |
| 1311 | mlir::Type fir::TypeDescType::parse(mlir::AsmParser &parser) { |
| 1312 | return parseTypeSingleton<fir::TypeDescType>(parser); |
| 1313 | } |
| 1314 | |
| 1315 | void fir::TypeDescType::print(mlir::AsmPrinter &printer) const { |
| 1316 | printer << "<" << getOfTy() << '>'; |
| 1317 | } |
| 1318 | |
| 1319 | llvm::LogicalResult fir::TypeDescType::verify( |
| 1320 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, |
| 1321 | mlir::Type eleTy) { |
| 1322 | if (mlir::isa<BoxType, BoxCharType, BoxProcType, ShapeType, ShapeShiftType, |
| 1323 | ShiftType, SliceType, FieldType, LenType, ReferenceType, |
| 1324 | TypeDescType>(eleTy)) |
| 1325 | return emitError() << "cannot build a type descriptor of type: " << eleTy |
| 1326 | << '\n'; |
| 1327 | return mlir::success(); |
| 1328 | } |
| 1329 | |
| 1330 | //===----------------------------------------------------------------------===// |
| 1331 | // VectorType |
| 1332 | //===----------------------------------------------------------------------===// |
| 1333 | |
| 1334 | // `vector` `<` len `:` type `>` |
| 1335 | mlir::Type fir::VectorType::parse(mlir::AsmParser &parser) { |
| 1336 | int64_t len = 0; |
| 1337 | mlir::Type eleTy; |
| 1338 | if (parser.parseLess() || parser.parseInteger(len) || parser.parseColon() || |
| 1339 | parser.parseType(eleTy) || parser.parseGreater()) |
| 1340 | return {}; |
| 1341 | return fir::VectorType::get(len, eleTy); |
| 1342 | } |
| 1343 | |
| 1344 | void fir::VectorType::print(mlir::AsmPrinter &printer) const { |
| 1345 | printer << "<" << getLen() << ':' << getEleTy() << '>'; |
| 1346 | } |
| 1347 | |
| 1348 | llvm::LogicalResult fir::VectorType::verify( |
| 1349 | llvm::function_ref<mlir::InFlightDiagnostic()> emitError, uint64_t len, |
| 1350 | mlir::Type eleTy) { |
| 1351 | if (!(fir::isa_real(eleTy) || fir::isa_integer(eleTy))) |
| 1352 | return emitError() << "cannot build a vector of type " << eleTy << '\n'; |
| 1353 | return mlir::success(); |
| 1354 | } |
| 1355 | |
| 1356 | bool fir::VectorType::isValidElementType(mlir::Type t) { |
| 1357 | return isa_real(t) || isa_integer(t); |
| 1358 | } |
| 1359 | |
| 1360 | bool fir::isCharacterProcedureTuple(mlir::Type ty, bool acceptRawFunc) { |
| 1361 | mlir::TupleType tuple = mlir::dyn_cast<mlir::TupleType>(ty); |
| 1362 | return tuple && tuple.size() == 2 && |
| 1363 | (mlir::isa<fir::BoxProcType>(tuple.getType(0)) || |
| 1364 | (acceptRawFunc && mlir::isa<mlir::FunctionType>(tuple.getType(0)))) && |
| 1365 | fir::isa_integer(tuple.getType(1)); |
| 1366 | } |
| 1367 | |
| 1368 | bool fir::hasAbstractResult(mlir::FunctionType ty) { |
| 1369 | if (ty.getNumResults() == 0) |
| 1370 | return false; |
| 1371 | auto resultType = ty.getResult(0); |
| 1372 | return mlir::isa<fir::SequenceType, fir::BaseBoxType, fir::RecordType>( |
| 1373 | resultType); |
| 1374 | } |
| 1375 | |
| 1376 | /// Convert llvm::Type::TypeID to mlir::Type. \p kind is provided for error |
| 1377 | /// messages only. |
| 1378 | mlir::Type fir::fromRealTypeID(mlir::MLIRContext *context, |
| 1379 | llvm::Type::TypeID typeID, fir::KindTy kind) { |
| 1380 | switch (typeID) { |
| 1381 | case llvm::Type::TypeID::HalfTyID: |
| 1382 | return mlir::Float16Type::get(context); |
| 1383 | case llvm::Type::TypeID::BFloatTyID: |
| 1384 | return mlir::BFloat16Type::get(context); |
| 1385 | case llvm::Type::TypeID::FloatTyID: |
| 1386 | return mlir::Float32Type::get(context); |
| 1387 | case llvm::Type::TypeID::DoubleTyID: |
| 1388 | return mlir::Float64Type::get(context); |
| 1389 | case llvm::Type::TypeID::X86_FP80TyID: |
| 1390 | return mlir::Float80Type::get(context); |
| 1391 | case llvm::Type::TypeID::FP128TyID: |
| 1392 | return mlir::Float128Type::get(context); |
| 1393 | default: |
| 1394 | mlir::emitError(mlir::UnknownLoc::get(context)) |
| 1395 | << "unsupported type: !fir.real<" << kind << ">" ; |
| 1396 | return {}; |
| 1397 | } |
| 1398 | } |
| 1399 | |
| 1400 | //===----------------------------------------------------------------------===// |
| 1401 | // BaseBoxType |
| 1402 | //===----------------------------------------------------------------------===// |
| 1403 | |
| 1404 | mlir::Type BaseBoxType::getEleTy() const { |
| 1405 | return llvm::TypeSwitch<fir::BaseBoxType, mlir::Type>(*this) |
| 1406 | .Case<fir::BoxType, fir::ClassType>( |
| 1407 | [](auto type) { return type.getEleTy(); }); |
| 1408 | } |
| 1409 | |
| 1410 | mlir::Type BaseBoxType::getBaseAddressType() const { |
| 1411 | mlir::Type eleTy = getEleTy(); |
| 1412 | if (fir::isa_ref_type(eleTy)) |
| 1413 | return eleTy; |
| 1414 | return fir::ReferenceType::get(eleTy, isVolatile()); |
| 1415 | } |
| 1416 | |
| 1417 | mlir::Type BaseBoxType::unwrapInnerType() const { |
| 1418 | return fir::unwrapInnerType(getEleTy()); |
| 1419 | } |
| 1420 | |
| 1421 | static mlir::Type |
| 1422 | changeTypeShape(mlir::Type type, |
| 1423 | std::optional<fir::SequenceType::ShapeRef> newShape) { |
| 1424 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(type) |
| 1425 | .Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type { |
| 1426 | if (newShape) |
| 1427 | return fir::SequenceType::get(*newShape, seqTy.getEleTy()); |
| 1428 | return seqTy.getEleTy(); |
| 1429 | }) |
| 1430 | .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>( |
| 1431 | [&](auto t) -> mlir::Type { |
| 1432 | using FIRT = decltype(t); |
| 1433 | return FIRT::get(changeTypeShape(t.getEleTy(), newShape), |
| 1434 | t.isVolatile()); |
| 1435 | }) |
| 1436 | .Case<fir::PointerType, fir::HeapType>([&](auto t) -> mlir::Type { |
| 1437 | using FIRT = decltype(t); |
| 1438 | return FIRT::get(changeTypeShape(t.getEleTy(), newShape)); |
| 1439 | }) |
| 1440 | .Default([&](mlir::Type t) -> mlir::Type { |
| 1441 | assert((fir::isa_trivial(t) || llvm::isa<fir::RecordType>(t) || |
| 1442 | llvm::isa<mlir::NoneType>(t) || |
| 1443 | llvm::isa<fir::CharacterType>(t)) && |
| 1444 | "unexpected FIR leaf type" ); |
| 1445 | if (newShape) |
| 1446 | return fir::SequenceType::get(*newShape, t); |
| 1447 | return t; |
| 1448 | }); |
| 1449 | } |
| 1450 | |
| 1451 | fir::BaseBoxType |
| 1452 | fir::BaseBoxType::getBoxTypeWithNewShape(mlir::Type shapeMold) const { |
| 1453 | fir::SequenceType seqTy = fir::unwrapUntilSeqType(shapeMold); |
| 1454 | std::optional<fir::SequenceType::ShapeRef> newShape; |
| 1455 | if (seqTy) |
| 1456 | newShape = seqTy.getShape(); |
| 1457 | return mlir::cast<fir::BaseBoxType>(changeTypeShape(*this, newShape)); |
| 1458 | } |
| 1459 | |
| 1460 | fir::BaseBoxType fir::BaseBoxType::getBoxTypeWithNewShape(int rank) const { |
| 1461 | std::optional<fir::SequenceType::ShapeRef> newShape; |
| 1462 | fir::SequenceType::Shape shapeVector; |
| 1463 | if (rank > 0) { |
| 1464 | shapeVector = |
| 1465 | fir::SequenceType::Shape(rank, fir::SequenceType::getUnknownExtent()); |
| 1466 | newShape = shapeVector; |
| 1467 | } |
| 1468 | return mlir::cast<fir::BaseBoxType>(changeTypeShape(*this, newShape)); |
| 1469 | } |
| 1470 | |
| 1471 | fir::BaseBoxType fir::BaseBoxType::getBoxTypeWithNewAttr( |
| 1472 | fir::BaseBoxType::Attribute attr) const { |
| 1473 | mlir::Type baseType = fir::unwrapRefType(getEleTy()); |
| 1474 | switch (attr) { |
| 1475 | case fir::BaseBoxType::Attribute::None: |
| 1476 | break; |
| 1477 | case fir::BaseBoxType::Attribute::Allocatable: |
| 1478 | baseType = fir::HeapType::get(baseType); |
| 1479 | break; |
| 1480 | case fir::BaseBoxType::Attribute::Pointer: |
| 1481 | baseType = fir::PointerType::get(baseType); |
| 1482 | break; |
| 1483 | } |
| 1484 | return llvm::TypeSwitch<fir::BaseBoxType, fir::BaseBoxType>(*this) |
| 1485 | .Case<fir::BoxType>([baseType](auto b) { |
| 1486 | return fir::BoxType::get(baseType, b.isVolatile()); |
| 1487 | }) |
| 1488 | .Case<fir::ClassType>([baseType](auto b) { |
| 1489 | return fir::ClassType::get(baseType, b.isVolatile()); |
| 1490 | }); |
| 1491 | } |
| 1492 | |
| 1493 | bool fir::BaseBoxType::isAssumedRank() const { |
| 1494 | if (auto seqTy = |
| 1495 | mlir::dyn_cast<fir::SequenceType>(fir::unwrapRefType(getEleTy()))) |
| 1496 | return seqTy.hasUnknownShape(); |
| 1497 | return false; |
| 1498 | } |
| 1499 | |
| 1500 | bool fir::BaseBoxType::isPointer() const { |
| 1501 | return llvm::isa<fir::PointerType>(getEleTy()); |
| 1502 | } |
| 1503 | |
| 1504 | bool fir::BaseBoxType::isPointerOrAllocatable() const { |
| 1505 | return llvm::isa<fir::PointerType, fir::HeapType>(getEleTy()); |
| 1506 | } |
| 1507 | |
| 1508 | bool BaseBoxType::isVolatile() const { return fir::isa_volatile_type(*this); } |
| 1509 | |
| 1510 | //===----------------------------------------------------------------------===// |
| 1511 | // FIROpsDialect |
| 1512 | //===----------------------------------------------------------------------===// |
| 1513 | |
| 1514 | void FIROpsDialect::registerTypes() { |
| 1515 | addTypes<BoxType, BoxCharType, BoxProcType, CharacterType, ClassType, |
| 1516 | FieldType, HeapType, fir::IntegerType, LenType, LogicalType, |
| 1517 | LLVMPointerType, PointerType, RecordType, ReferenceType, |
| 1518 | SequenceType, ShapeType, ShapeShiftType, ShiftType, SliceType, |
| 1519 | TypeDescType, fir::VectorType, fir::DummyScopeType>(); |
| 1520 | fir::ReferenceType::attachInterface< |
| 1521 | OpenMPPointerLikeModel<fir::ReferenceType>>(*getContext()); |
| 1522 | fir::PointerType::attachInterface<OpenMPPointerLikeModel<fir::PointerType>>( |
| 1523 | *getContext()); |
| 1524 | fir::HeapType::attachInterface<OpenMPPointerLikeModel<fir::HeapType>>( |
| 1525 | *getContext()); |
| 1526 | fir::LLVMPointerType::attachInterface< |
| 1527 | OpenMPPointerLikeModel<fir::LLVMPointerType>>(*getContext()); |
| 1528 | } |
| 1529 | |
| 1530 | std::optional<std::pair<uint64_t, unsigned short>> |
| 1531 | fir::getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty, |
| 1532 | const mlir::DataLayout &dl, |
| 1533 | const fir::KindMapping &kindMap) { |
| 1534 | if (mlir::isa<mlir::IntegerType, mlir::FloatType, mlir::ComplexType>(ty)) { |
| 1535 | llvm::TypeSize size = dl.getTypeSize(ty); |
| 1536 | unsigned short alignment = dl.getTypeABIAlignment(ty); |
| 1537 | return std::pair{size, alignment}; |
| 1538 | } |
| 1539 | if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) { |
| 1540 | auto result = getTypeSizeAndAlignment(loc, seqTy.getEleTy(), dl, kindMap); |
| 1541 | if (!result) |
| 1542 | return result; |
| 1543 | auto [eleSize, eleAlign] = *result; |
| 1544 | std::uint64_t size = |
| 1545 | llvm::alignTo(eleSize, eleAlign) * seqTy.getConstantArraySize(); |
| 1546 | return std::pair{size, eleAlign}; |
| 1547 | } |
| 1548 | if (auto recTy = mlir::dyn_cast<fir::RecordType>(ty)) { |
| 1549 | std::uint64_t size = 0; |
| 1550 | unsigned short align = 1; |
| 1551 | for (auto component : recTy.getTypeList()) { |
| 1552 | auto result = getTypeSizeAndAlignment(loc, component.second, dl, kindMap); |
| 1553 | if (!result) |
| 1554 | return result; |
| 1555 | auto [compSize, compAlign] = *result; |
| 1556 | size = |
| 1557 | llvm::alignTo(size, compAlign) + llvm::alignTo(compSize, compAlign); |
| 1558 | align = std::max(align, compAlign); |
| 1559 | } |
| 1560 | return std::pair{size, align}; |
| 1561 | } |
| 1562 | if (auto logical = mlir::dyn_cast<fir::LogicalType>(ty)) { |
| 1563 | mlir::Type intTy = mlir::IntegerType::get( |
| 1564 | logical.getContext(), kindMap.getLogicalBitsize(logical.getFKind())); |
| 1565 | return getTypeSizeAndAlignment(loc, intTy, dl, kindMap); |
| 1566 | } |
| 1567 | if (auto character = mlir::dyn_cast<fir::CharacterType>(ty)) { |
| 1568 | mlir::Type intTy = mlir::IntegerType::get( |
| 1569 | character.getContext(), |
| 1570 | kindMap.getCharacterBitsize(character.getFKind())); |
| 1571 | auto result = getTypeSizeAndAlignment(loc, intTy, dl, kindMap); |
| 1572 | if (!result) |
| 1573 | return result; |
| 1574 | auto [compSize, compAlign] = *result; |
| 1575 | if (character.hasConstantLen()) |
| 1576 | compSize *= character.getLen(); |
| 1577 | return std::pair{compSize, compAlign}; |
| 1578 | } |
| 1579 | return std::nullopt; |
| 1580 | } |
| 1581 | |
| 1582 | std::pair<std::uint64_t, unsigned short> |
| 1583 | fir::getTypeSizeAndAlignmentOrCrash(mlir::Location loc, mlir::Type ty, |
| 1584 | const mlir::DataLayout &dl, |
| 1585 | const fir::KindMapping &kindMap) { |
| 1586 | std::optional<std::pair<uint64_t, unsigned short>> result = |
| 1587 | getTypeSizeAndAlignment(loc, ty, dl, kindMap); |
| 1588 | if (result) |
| 1589 | return *result; |
| 1590 | TODO(loc, "computing size of a component" ); |
| 1591 | } |
| 1592 | |