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::FloatType::getF32(&context); |
231 | mlir::Type l1Ty = fir::LogicalType::get(&context, 1); |
232 | mlir::Type cplx4Ty = fir::ComplexType::get(&context, 4); |
233 | mlir::Type char1Ty = fir::CharacterType::get(&context, 1, 10); |
234 | llvm::SmallVector<mlir::Type> intrinsicTypes = { |
235 | i32Ty, f32Ty, l1Ty, cplx4Ty, 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::FloatType::getF64(&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::FloatType::getF32(&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 | |