| 1 | //===- FIRTypesTest.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 | #include "gtest/gtest.h" |
| 10 | #include "flang/Optimizer/Dialect/FIRType.h" |
| 11 | #include "flang/Optimizer/Dialect/Support/KindMapping.h" |
| 12 | #include "flang/Optimizer/Support/InitFIR.h" |
| 13 | |
| 14 | struct FIRTypesTest : public testing::Test { |
| 15 | public: |
| 16 | void SetUp() { |
| 17 | fir::support::loadDialects(context); |
| 18 | kindMap = new fir::KindMapping(&context, kindMapInit, "r42a10c14d28i40l41" ); |
| 19 | } |
| 20 | mlir::MLIRContext context; |
| 21 | fir::KindMapping *kindMap{}; |
| 22 | std::string kindMapInit = |
| 23 | "i10:80,l3:24,a1:8,r54:Double,r62:X86_FP80,r11:PPC_FP128" ; |
| 24 | }; |
| 25 | |
| 26 | // Test fir::isPolymorphicType from flang/Optimizer/Dialect/FIRType.h. |
| 27 | TEST_F(FIRTypesTest, isPolymorphicTypeTest) { |
| 28 | mlir::Type noneTy = mlir::NoneType::get(&context); |
| 29 | mlir::Type seqNoneTy = |
| 30 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, noneTy); |
| 31 | mlir::Type recTy = fir::RecordType::get(&context, "dt" ); |
| 32 | mlir::Type seqRecTy = |
| 33 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, recTy); |
| 34 | |
| 35 | // CLASS(T) |
| 36 | mlir::Type ty = fir::ClassType::get(recTy); |
| 37 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 38 | EXPECT_TRUE(fir::isPolymorphicType(fir::ReferenceType::get(ty))); |
| 39 | |
| 40 | // CLASS(T), DIMENSION(10) |
| 41 | ty = fir::ClassType::get(fir::SequenceType::get({10}, recTy)); |
| 42 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 43 | |
| 44 | // CLASS(T), DIMENSION(:) |
| 45 | ty = fir::ClassType::get(seqRecTy); |
| 46 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 47 | |
| 48 | // CLASS(T), ALLOCATABLE |
| 49 | ty = fir::ClassType::get(fir::HeapType::get(recTy)); |
| 50 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 51 | |
| 52 | // CLASS(T), ALLOCATABLE, DIMENSION(:) |
| 53 | ty = fir::ClassType::get(fir::HeapType::get(seqRecTy)); |
| 54 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 55 | |
| 56 | // CLASS(T), POINTER |
| 57 | ty = fir::ClassType::get(fir::PointerType::get(recTy)); |
| 58 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 59 | |
| 60 | // CLASS(T), POINTER, DIMENSIONS(:) |
| 61 | ty = fir::ClassType::get(fir::PointerType::get(seqRecTy)); |
| 62 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 63 | |
| 64 | // CLASS(*) |
| 65 | ty = fir::ClassType::get(noneTy); |
| 66 | EXPECT_TRUE(fir::isPolymorphicType(ty)); |
| 67 | EXPECT_TRUE(fir::isPolymorphicType(fir::ReferenceType::get(ty))); |
| 68 | |
| 69 | // TYPE(*) |
| 70 | EXPECT_TRUE(fir::isPolymorphicType(fir::BoxType::get(noneTy))); |
| 71 | |
| 72 | // TYPE(*), DIMENSION(:) |
| 73 | EXPECT_TRUE(fir::isPolymorphicType(fir::BoxType::get(seqNoneTy))); |
| 74 | |
| 75 | // false tests |
| 76 | EXPECT_FALSE(fir::isPolymorphicType(noneTy)); |
| 77 | EXPECT_FALSE(fir::isPolymorphicType(seqNoneTy)); |
| 78 | } |
| 79 | |
| 80 | // Test fir::isUnlimitedPolymorphicType from flang/Optimizer/Dialect/FIRType.h. |
| 81 | TEST_F(FIRTypesTest, isUnlimitedPolymorphicTypeTest) { |
| 82 | mlir::Type noneTy = mlir::NoneType::get(&context); |
| 83 | mlir::Type seqNoneTy = |
| 84 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, noneTy); |
| 85 | |
| 86 | // CLASS(*) |
| 87 | mlir::Type ty = fir::ClassType::get(noneTy); |
| 88 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 89 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(fir::ReferenceType::get(ty))); |
| 90 | |
| 91 | // CLASS(*), DIMENSION(10) |
| 92 | ty = fir::ClassType::get(fir::SequenceType::get({10}, noneTy)); |
| 93 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 94 | |
| 95 | // CLASS(*), DIMENSION(:) |
| 96 | ty = fir::ClassType::get( |
| 97 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, noneTy)); |
| 98 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 99 | |
| 100 | // CLASS(*), ALLOCATABLE |
| 101 | ty = fir::ClassType::get(fir::HeapType::get(noneTy)); |
| 102 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 103 | |
| 104 | // CLASS(*), ALLOCATABLE, DIMENSION(:) |
| 105 | ty = fir::ClassType::get(fir::HeapType::get(seqNoneTy)); |
| 106 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 107 | |
| 108 | // CLASS(*), POINTER |
| 109 | ty = fir::ClassType::get(fir::PointerType::get(noneTy)); |
| 110 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 111 | |
| 112 | // CLASS(*), POINTER, DIMENSIONS(:) |
| 113 | ty = fir::ClassType::get(fir::PointerType::get(seqNoneTy)); |
| 114 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(ty)); |
| 115 | |
| 116 | // TYPE(*) |
| 117 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(fir::BoxType::get(noneTy))); |
| 118 | |
| 119 | // TYPE(*), DIMENSION(:) |
| 120 | EXPECT_TRUE(fir::isUnlimitedPolymorphicType(fir::BoxType::get(seqNoneTy))); |
| 121 | |
| 122 | // false tests |
| 123 | EXPECT_FALSE(fir::isUnlimitedPolymorphicType(noneTy)); |
| 124 | EXPECT_FALSE(fir::isUnlimitedPolymorphicType(seqNoneTy)); |
| 125 | } |
| 126 | |
| 127 | // Test fir::isBoxedRecordType from flang/Optimizer/Dialect/FIRType.h. |
| 128 | TEST_F(FIRTypesTest, isBoxedRecordType) { |
| 129 | mlir::Type recTy = fir::RecordType::get(&context, "dt" ); |
| 130 | mlir::Type seqRecTy = |
| 131 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, recTy); |
| 132 | mlir::Type ty = fir::BoxType::get(recTy); |
| 133 | EXPECT_TRUE(fir::isBoxedRecordType(ty)); |
| 134 | EXPECT_TRUE(fir::isBoxedRecordType(fir::ReferenceType::get(ty))); |
| 135 | |
| 136 | // TYPE(T), ALLOCATABLE |
| 137 | ty = fir::BoxType::get(fir::HeapType::get(recTy)); |
| 138 | EXPECT_TRUE(fir::isBoxedRecordType(ty)); |
| 139 | |
| 140 | // TYPE(T), POINTER |
| 141 | ty = fir::BoxType::get(fir::PointerType::get(recTy)); |
| 142 | EXPECT_TRUE(fir::isBoxedRecordType(ty)); |
| 143 | |
| 144 | // TYPE(T), DIMENSION(10) |
| 145 | ty = fir::BoxType::get(fir::SequenceType::get({10}, recTy)); |
| 146 | EXPECT_TRUE(fir::isBoxedRecordType(ty)); |
| 147 | |
| 148 | // TYPE(T), DIMENSION(:) |
| 149 | ty = fir::BoxType::get(seqRecTy); |
| 150 | EXPECT_TRUE(fir::isBoxedRecordType(ty)); |
| 151 | |
| 152 | EXPECT_FALSE(fir::isBoxedRecordType(fir::BoxType::get( |
| 153 | fir::ReferenceType::get(mlir::IntegerType::get(&context, 32))))); |
| 154 | } |
| 155 | |
| 156 | // Test fir::isScalarBoxedRecordType from flang/Optimizer/Dialect/FIRType.h. |
| 157 | TEST_F(FIRTypesTest, isScalarBoxedRecordType) { |
| 158 | mlir::Type recTy = fir::RecordType::get(&context, "dt" ); |
| 159 | mlir::Type seqRecTy = |
| 160 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, recTy); |
| 161 | mlir::Type ty = fir::BoxType::get(recTy); |
| 162 | EXPECT_TRUE(fir::isScalarBoxedRecordType(ty)); |
| 163 | EXPECT_TRUE(fir::isScalarBoxedRecordType(fir::ReferenceType::get(ty))); |
| 164 | |
| 165 | // CLASS(T), ALLOCATABLE |
| 166 | ty = fir::ClassType::get(fir::HeapType::get(recTy)); |
| 167 | EXPECT_TRUE(fir::isScalarBoxedRecordType(ty)); |
| 168 | |
| 169 | // TYPE(T), ALLOCATABLE |
| 170 | ty = fir::BoxType::get(fir::HeapType::get(recTy)); |
| 171 | EXPECT_TRUE(fir::isScalarBoxedRecordType(ty)); |
| 172 | |
| 173 | // TYPE(T), POINTER |
| 174 | ty = fir::BoxType::get(fir::PointerType::get(recTy)); |
| 175 | EXPECT_TRUE(fir::isScalarBoxedRecordType(ty)); |
| 176 | |
| 177 | // CLASS(T), POINTER |
| 178 | ty = fir::ClassType::get(fir::PointerType::get(recTy)); |
| 179 | EXPECT_TRUE(fir::isScalarBoxedRecordType(ty)); |
| 180 | |
| 181 | // TYPE(T), DIMENSION(10) |
| 182 | ty = fir::BoxType::get(fir::SequenceType::get({10}, recTy)); |
| 183 | EXPECT_FALSE(fir::isScalarBoxedRecordType(ty)); |
| 184 | |
| 185 | // TYPE(T), DIMENSION(:) |
| 186 | ty = fir::BoxType::get(seqRecTy); |
| 187 | EXPECT_FALSE(fir::isScalarBoxedRecordType(ty)); |
| 188 | |
| 189 | EXPECT_FALSE(fir::isScalarBoxedRecordType(fir::BoxType::get( |
| 190 | fir::ReferenceType::get(mlir::IntegerType::get(&context, 32))))); |
| 191 | } |
| 192 | |
| 193 | TEST_F(FIRTypesTest, updateTypeForUnlimitedPolymorphic) { |
| 194 | // RecordType are not changed. |
| 195 | |
| 196 | // !fir.tyep<T> -> !fir.type<T> |
| 197 | mlir::Type recTy = fir::RecordType::get(&context, "dt" ); |
| 198 | EXPECT_EQ(recTy, fir::updateTypeForUnlimitedPolymorphic(recTy)); |
| 199 | |
| 200 | // !fir.array<2x!fir.type<T>> -> !fir.array<2x!fir.type<T>> |
| 201 | mlir::Type arrRecTy = fir::SequenceType::get({2}, recTy); |
| 202 | EXPECT_EQ(arrRecTy, fir::updateTypeForUnlimitedPolymorphic(arrRecTy)); |
| 203 | |
| 204 | // !fir.heap<!fir.type<T>> -> !fir.heap<!fir.type<T>> |
| 205 | mlir::Type heapTy = fir::HeapType::get(recTy); |
| 206 | EXPECT_EQ(heapTy, fir::updateTypeForUnlimitedPolymorphic(heapTy)); |
| 207 | // !fir.heap<!fir.array<2x!fir.type<T>>> -> |
| 208 | // !fir.heap<!fir.array<2x!fir.type<T>>> |
| 209 | mlir::Type heapArrTy = fir::HeapType::get(arrRecTy); |
| 210 | EXPECT_EQ(heapArrTy, fir::updateTypeForUnlimitedPolymorphic(heapArrTy)); |
| 211 | |
| 212 | // !fir.ptr<!fir.type<T>> -> !fir.ptr<!fir.type<T>> |
| 213 | mlir::Type ptrTy = fir::PointerType::get(recTy); |
| 214 | EXPECT_EQ(ptrTy, fir::updateTypeForUnlimitedPolymorphic(ptrTy)); |
| 215 | // !fir.ptr<!fir.array<2x!fir.type<T>>> -> |
| 216 | // !fir.ptr<!fir.array<2x!fir.type<T>>> |
| 217 | mlir::Type ptrArrTy = fir::PointerType::get(arrRecTy); |
| 218 | EXPECT_EQ(ptrArrTy, fir::updateTypeForUnlimitedPolymorphic(ptrArrTy)); |
| 219 | |
| 220 | // When updating intrinsic types the array, pointer and heap types are kept. |
| 221 | // only the inner element type is changed to `none`. |
| 222 | mlir::Type none = mlir::NoneType::get(&context); |
| 223 | mlir::Type arrNone = fir::SequenceType::get({10}, none); |
| 224 | mlir::Type heapNone = fir::HeapType::get(none); |
| 225 | mlir::Type heapArrNone = fir::HeapType::get(arrNone); |
| 226 | mlir::Type ptrNone = fir::PointerType::get(none); |
| 227 | mlir::Type ptrArrNone = fir::PointerType::get(arrNone); |
| 228 | |
| 229 | mlir::Type i32Ty = mlir::IntegerType::get(&context, 32); |
| 230 | mlir::Type f32Ty = mlir::Float32Type::get(&context); |
| 231 | mlir::Type l1Ty = fir::LogicalType::get(&context, 1); |
| 232 | mlir::Type cplx32Ty = mlir::ComplexType::get(f32Ty); |
| 233 | mlir::Type char1Ty = fir::CharacterType::get(&context, 1, 10); |
| 234 | llvm::SmallVector<mlir::Type> intrinsicTypes = { |
| 235 | i32Ty, f32Ty, l1Ty, cplx32Ty, char1Ty}; |
| 236 | |
| 237 | for (mlir::Type ty : intrinsicTypes) { |
| 238 | // `ty` -> none |
| 239 | EXPECT_EQ(none, fir::updateTypeForUnlimitedPolymorphic(ty)); |
| 240 | |
| 241 | // !fir.array<10xTY> -> !fir.array<10xnone> |
| 242 | mlir::Type arrTy = fir::SequenceType::get({10}, ty); |
| 243 | EXPECT_EQ(arrNone, fir::updateTypeForUnlimitedPolymorphic(arrTy)); |
| 244 | |
| 245 | // !fir.heap<TY> -> !fir.heap<none> |
| 246 | mlir::Type heapTy = fir::HeapType::get(ty); |
| 247 | EXPECT_EQ(heapNone, fir::updateTypeForUnlimitedPolymorphic(heapTy)); |
| 248 | |
| 249 | // !fir.heap<!fir.array<10xTY>> -> !fir.heap<!fir.array<10xnone>> |
| 250 | mlir::Type heapArrTy = fir::HeapType::get(arrTy); |
| 251 | EXPECT_EQ(heapArrNone, fir::updateTypeForUnlimitedPolymorphic(heapArrTy)); |
| 252 | |
| 253 | // !fir.ptr<TY> -> !fir.ptr<none> |
| 254 | mlir::Type ptrTy = fir::PointerType::get(ty); |
| 255 | EXPECT_EQ(ptrNone, fir::updateTypeForUnlimitedPolymorphic(ptrTy)); |
| 256 | |
| 257 | // !fir.ptr<!fir.array<10xTY>> -> !fir.ptr<!fir.array<10xnone>> |
| 258 | mlir::Type ptrArrTy = fir::PointerType::get(arrTy); |
| 259 | EXPECT_EQ(ptrArrNone, fir::updateTypeForUnlimitedPolymorphic(ptrArrTy)); |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | TEST_F(FIRTypesTest, getTypeAsString) { |
| 264 | EXPECT_EQ("i32" , |
| 265 | fir::getTypeAsString(mlir::IntegerType::get(&context, 32), *kindMap)); |
| 266 | EXPECT_EQ("ref_i32" , |
| 267 | fir::getTypeAsString( |
| 268 | fir::ReferenceType::get(mlir::IntegerType::get(&context, 32)), |
| 269 | *kindMap)); |
| 270 | EXPECT_EQ( |
| 271 | "f64" , fir::getTypeAsString(mlir::Float64Type::get(&context), *kindMap)); |
| 272 | EXPECT_EQ( |
| 273 | "l8" , fir::getTypeAsString(fir::LogicalType::get(&context, 1), *kindMap)); |
| 274 | EXPECT_EQ("z32" , |
| 275 | fir::getTypeAsString( |
| 276 | mlir::ComplexType::get(mlir::Float32Type::get(&context)), *kindMap)); |
| 277 | EXPECT_EQ("c8" , |
| 278 | fir::getTypeAsString(fir::CharacterType::get(&context, 1, 1), *kindMap)); |
| 279 | EXPECT_EQ("c8x10" , |
| 280 | fir::getTypeAsString(fir::CharacterType::get(&context, 1, 10), *kindMap)); |
| 281 | mlir::Type ty = mlir::IntegerType::get(&context, 64); |
| 282 | mlir::Type arrTy = fir::SequenceType::get({10, 20}, ty); |
| 283 | EXPECT_EQ("10x20xi64" , fir::getTypeAsString(arrTy, *kindMap)); |
| 284 | EXPECT_EQ( |
| 285 | "idx" , fir::getTypeAsString(mlir::IndexType::get(&context), *kindMap)); |
| 286 | EXPECT_EQ("ptr_i32" , |
| 287 | fir::getTypeAsString( |
| 288 | fir::PointerType::get(mlir::IntegerType::get(&context, 32)), |
| 289 | *kindMap)); |
| 290 | EXPECT_EQ("heap_i32" , |
| 291 | fir::getTypeAsString( |
| 292 | fir::HeapType::get(mlir::IntegerType::get(&context, 32)), *kindMap)); |
| 293 | EXPECT_EQ("box_i32" , |
| 294 | fir::getTypeAsString( |
| 295 | fir::BoxType::get(mlir::IntegerType::get(&context, 32)), *kindMap)); |
| 296 | EXPECT_EQ("class_i32" , |
| 297 | fir::getTypeAsString( |
| 298 | fir::ClassType::get(mlir::IntegerType::get(&context, 32)), *kindMap)); |
| 299 | EXPECT_EQ("class_none" , |
| 300 | fir::getTypeAsString( |
| 301 | fir::ClassType::get(mlir::NoneType::get(&context)), *kindMap)); |
| 302 | auto derivedTy = fir::RecordType::get(&context, "derived" ); |
| 303 | llvm::SmallVector<std::pair<std::string, mlir::Type>> components; |
| 304 | components.emplace_back("p1" , mlir::IntegerType::get(&context, 64)); |
| 305 | derivedTy.finalize({}, components); |
| 306 | EXPECT_EQ("rec_derived" , fir::getTypeAsString(derivedTy, *kindMap)); |
| 307 | mlir::Type dynArrTy = |
| 308 | fir::SequenceType::get({fir::SequenceType::getUnknownExtent(), |
| 309 | fir::SequenceType::getUnknownExtent()}, |
| 310 | ty); |
| 311 | EXPECT_EQ("UxUxi64" , fir::getTypeAsString(dynArrTy, *kindMap)); |
| 312 | EXPECT_EQ("llvmptr_i32" , |
| 313 | fir::getTypeAsString( |
| 314 | fir::LLVMPointerType::get(mlir::IntegerType::get(&context, 32)), |
| 315 | *kindMap)); |
| 316 | EXPECT_EQ("boxchar_c8xU" , |
| 317 | fir::getTypeAsString(fir::BoxCharType::get(&context, 1), *kindMap)); |
| 318 | } |
| 319 | |
| 320 | TEST_F(FIRTypesTest, isVolatileType) { |
| 321 | mlir::Type i32 = mlir::IntegerType::get(&context, 32); |
| 322 | |
| 323 | mlir::Type i32NonVolatileRef = fir::ReferenceType::get(i32); |
| 324 | mlir::Type i32NonVolatileBox = fir::BoxType::get(i32); |
| 325 | mlir::Type i32NonVolatileClass = fir::ClassType::get(i32); |
| 326 | |
| 327 | // Ensure the default value is false |
| 328 | EXPECT_EQ(i32NonVolatileRef, fir::ReferenceType::get(i32, false)); |
| 329 | EXPECT_EQ(i32NonVolatileBox, fir::BoxType::get(i32, false)); |
| 330 | EXPECT_EQ(i32NonVolatileClass, fir::ClassType::get(i32, false)); |
| 331 | |
| 332 | EXPECT_FALSE(fir::isa_volatile_type(i32)); |
| 333 | EXPECT_FALSE(fir::isa_volatile_type(i32NonVolatileRef)); |
| 334 | EXPECT_FALSE(fir::isa_volatile_type(i32NonVolatileBox)); |
| 335 | EXPECT_FALSE(fir::isa_volatile_type(i32NonVolatileClass)); |
| 336 | |
| 337 | // Should return the same type if it's not capable of representing volatility. |
| 338 | EXPECT_EQ(i32, fir::updateTypeWithVolatility(i32, true)); |
| 339 | |
| 340 | mlir::Type i32VolatileRef = |
| 341 | fir::updateTypeWithVolatility(i32NonVolatileRef, true); |
| 342 | mlir::Type i32VolatileBox = |
| 343 | fir::updateTypeWithVolatility(i32NonVolatileBox, true); |
| 344 | mlir::Type i32VolatileClass = |
| 345 | fir::updateTypeWithVolatility(i32NonVolatileClass, true); |
| 346 | |
| 347 | EXPECT_TRUE(fir::isa_volatile_type(i32VolatileRef)); |
| 348 | EXPECT_TRUE(fir::isa_volatile_type(i32VolatileBox)); |
| 349 | EXPECT_TRUE(fir::isa_volatile_type(i32VolatileClass)); |
| 350 | |
| 351 | EXPECT_EQ(i32VolatileRef, fir::ReferenceType::get(i32, true)); |
| 352 | EXPECT_EQ(i32VolatileBox, fir::BoxType::get(i32, true)); |
| 353 | EXPECT_EQ(i32VolatileClass, fir::ClassType::get(i32, true)); |
| 354 | } |
| 355 | |