1 | //===- FIRBuilderTest.cpp -- FIRBuilder unit tests ------------------------===// |
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 "flang/Optimizer/Builder/FIRBuilder.h" |
10 | #include "gtest/gtest.h" |
11 | #include "flang/Optimizer/Builder/BoxValue.h" |
12 | #include "flang/Optimizer/Dialect/Support/KindMapping.h" |
13 | #include "flang/Optimizer/Support/InitFIR.h" |
14 | |
15 | using namespace mlir; |
16 | |
17 | struct FIRBuilderTest : public testing::Test { |
18 | public: |
19 | void SetUp() override { |
20 | fir::support::loadDialects(context); |
21 | |
22 | llvm::ArrayRef<fir::KindTy> defs; |
23 | fir::KindMapping kindMap(&context, defs); |
24 | mlir::OpBuilder builder(&context); |
25 | auto loc = builder.getUnknownLoc(); |
26 | |
27 | // Set up a Module with a dummy function operation inside. |
28 | // Set the insertion point in the function entry block. |
29 | mlir::ModuleOp mod = builder.create<mlir::ModuleOp>(loc); |
30 | mlir::func::FuncOp func = mlir::func::FuncOp::create( |
31 | loc, "func1" , builder.getFunctionType(std::nullopt, std::nullopt)); |
32 | auto *entryBlock = func.addEntryBlock(); |
33 | mod.push_back(mod); |
34 | builder.setInsertionPointToStart(entryBlock); |
35 | |
36 | firBuilder = std::make_unique<fir::FirOpBuilder>(mod, kindMap); |
37 | } |
38 | |
39 | fir::FirOpBuilder &getBuilder() { return *firBuilder; } |
40 | |
41 | mlir::MLIRContext context; |
42 | std::unique_ptr<fir::FirOpBuilder> firBuilder; |
43 | }; |
44 | |
45 | static arith::CmpIOp createCondition(fir::FirOpBuilder &builder) { |
46 | auto loc = builder.getUnknownLoc(); |
47 | auto zero1 = builder.createIntegerConstant(loc, builder.getIndexType(), 0); |
48 | auto zero2 = builder.createIntegerConstant(loc, builder.getIndexType(), 0); |
49 | return builder.create<arith::CmpIOp>( |
50 | loc, arith::CmpIPredicate::eq, zero1, zero2); |
51 | } |
52 | |
53 | static void checkIntegerConstant(mlir::Value value, mlir::Type ty, int64_t v) { |
54 | EXPECT_TRUE(mlir::isa<mlir::arith::ConstantOp>(value.getDefiningOp())); |
55 | auto cstOp = dyn_cast<mlir::arith::ConstantOp>(value.getDefiningOp()); |
56 | EXPECT_EQ(ty, cstOp.getType()); |
57 | auto valueAttr = cstOp.getValue().dyn_cast_or_null<IntegerAttr>(); |
58 | EXPECT_EQ(v, valueAttr.getInt()); |
59 | } |
60 | |
61 | //===----------------------------------------------------------------------===// |
62 | // IfBuilder tests |
63 | //===----------------------------------------------------------------------===// |
64 | |
65 | TEST_F(FIRBuilderTest, genIfThen) { |
66 | auto builder = getBuilder(); |
67 | auto loc = builder.getUnknownLoc(); |
68 | auto cdt = createCondition(builder); |
69 | auto ifBuilder = builder.genIfThen(loc, cdt); |
70 | EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty()); |
71 | EXPECT_TRUE(ifBuilder.getIfOp().getElseRegion().empty()); |
72 | } |
73 | |
74 | TEST_F(FIRBuilderTest, genIfThenElse) { |
75 | auto builder = getBuilder(); |
76 | auto loc = builder.getUnknownLoc(); |
77 | auto cdt = createCondition(builder); |
78 | auto ifBuilder = builder.genIfThenElse(loc, cdt); |
79 | EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty()); |
80 | EXPECT_FALSE(ifBuilder.getIfOp().getElseRegion().empty()); |
81 | } |
82 | |
83 | TEST_F(FIRBuilderTest, genIfWithThen) { |
84 | auto builder = getBuilder(); |
85 | auto loc = builder.getUnknownLoc(); |
86 | auto cdt = createCondition(builder); |
87 | auto ifBuilder = builder.genIfOp(loc, {}, cdt, false); |
88 | EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty()); |
89 | EXPECT_TRUE(ifBuilder.getIfOp().getElseRegion().empty()); |
90 | } |
91 | |
92 | TEST_F(FIRBuilderTest, genIfWithThenAndElse) { |
93 | auto builder = getBuilder(); |
94 | auto loc = builder.getUnknownLoc(); |
95 | auto cdt = createCondition(builder); |
96 | auto ifBuilder = builder.genIfOp(loc, {}, cdt, true); |
97 | EXPECT_FALSE(ifBuilder.getIfOp().getThenRegion().empty()); |
98 | EXPECT_FALSE(ifBuilder.getIfOp().getElseRegion().empty()); |
99 | } |
100 | |
101 | //===----------------------------------------------------------------------===// |
102 | // Helper functions tests |
103 | //===----------------------------------------------------------------------===// |
104 | |
105 | TEST_F(FIRBuilderTest, genIsNotNullAddr) { |
106 | auto builder = getBuilder(); |
107 | auto loc = builder.getUnknownLoc(); |
108 | auto dummyValue = |
109 | builder.createIntegerConstant(loc, builder.getIndexType(), 0); |
110 | auto res = builder.genIsNotNullAddr(loc, dummyValue); |
111 | EXPECT_TRUE(mlir::isa<arith::CmpIOp>(res.getDefiningOp())); |
112 | auto cmpOp = dyn_cast<arith::CmpIOp>(res.getDefiningOp()); |
113 | EXPECT_EQ(arith::CmpIPredicate::ne, cmpOp.getPredicate()); |
114 | } |
115 | |
116 | TEST_F(FIRBuilderTest, genIsNullAddr) { |
117 | auto builder = getBuilder(); |
118 | auto loc = builder.getUnknownLoc(); |
119 | auto dummyValue = |
120 | builder.createIntegerConstant(loc, builder.getIndexType(), 0); |
121 | auto res = builder.genIsNullAddr(loc, dummyValue); |
122 | EXPECT_TRUE(mlir::isa<arith::CmpIOp>(res.getDefiningOp())); |
123 | auto cmpOp = dyn_cast<arith::CmpIOp>(res.getDefiningOp()); |
124 | EXPECT_EQ(arith::CmpIPredicate::eq, cmpOp.getPredicate()); |
125 | } |
126 | |
127 | TEST_F(FIRBuilderTest, createZeroConstant) { |
128 | auto builder = getBuilder(); |
129 | auto loc = builder.getUnknownLoc(); |
130 | |
131 | auto cst = builder.createNullConstant(loc); |
132 | EXPECT_TRUE(mlir::isa<fir::ZeroOp>(cst.getDefiningOp())); |
133 | auto zeroOp = dyn_cast<fir::ZeroOp>(cst.getDefiningOp()); |
134 | EXPECT_EQ(fir::ReferenceType::get(builder.getNoneType()), |
135 | zeroOp.getResult().getType()); |
136 | auto idxTy = builder.getIndexType(); |
137 | |
138 | cst = builder.createNullConstant(loc, idxTy); |
139 | EXPECT_TRUE(mlir::isa<fir::ZeroOp>(cst.getDefiningOp())); |
140 | zeroOp = dyn_cast<fir::ZeroOp>(cst.getDefiningOp()); |
141 | EXPECT_EQ(builder.getIndexType(), zeroOp.getResult().getType()); |
142 | } |
143 | |
144 | TEST_F(FIRBuilderTest, createRealZeroConstant) { |
145 | auto builder = getBuilder(); |
146 | auto ctx = builder.getContext(); |
147 | auto loc = builder.getUnknownLoc(); |
148 | auto realTy = mlir::FloatType::getF64(ctx); |
149 | auto cst = builder.createRealZeroConstant(loc, realTy); |
150 | EXPECT_TRUE(mlir::isa<arith::ConstantOp>(cst.getDefiningOp())); |
151 | auto cstOp = dyn_cast<arith::ConstantOp>(cst.getDefiningOp()); |
152 | EXPECT_EQ(realTy, cstOp.getType()); |
153 | EXPECT_EQ( |
154 | 0u, cstOp.getValue().cast<FloatAttr>().getValue().convertToDouble()); |
155 | } |
156 | |
157 | TEST_F(FIRBuilderTest, createBool) { |
158 | auto builder = getBuilder(); |
159 | auto loc = builder.getUnknownLoc(); |
160 | auto b = builder.createBool(loc, false); |
161 | checkIntegerConstant(b, builder.getIntegerType(1), 0); |
162 | } |
163 | |
164 | TEST_F(FIRBuilderTest, getVarLenSeqTy) { |
165 | auto builder = getBuilder(); |
166 | auto ty = builder.getVarLenSeqTy(builder.getI64Type()); |
167 | EXPECT_TRUE(ty.isa<fir::SequenceType>()); |
168 | fir::SequenceType seqTy = ty.dyn_cast<fir::SequenceType>(); |
169 | EXPECT_EQ(1u, seqTy.getDimension()); |
170 | EXPECT_TRUE(fir::unwrapSequenceType(ty).isInteger(64)); |
171 | } |
172 | |
173 | TEST_F(FIRBuilderTest, getNamedFunction) { |
174 | auto builder = getBuilder(); |
175 | auto func2 = builder.getNamedFunction("func2" ); |
176 | EXPECT_EQ(nullptr, func2); |
177 | auto loc = builder.getUnknownLoc(); |
178 | func2 = builder.createFunction( |
179 | loc, "func2" , builder.getFunctionType(std::nullopt, std::nullopt)); |
180 | auto func2query = builder.getNamedFunction("func2" ); |
181 | EXPECT_EQ(func2, func2query); |
182 | } |
183 | |
184 | TEST_F(FIRBuilderTest, createGlobal1) { |
185 | auto builder = getBuilder(); |
186 | auto loc = builder.getUnknownLoc(); |
187 | auto i64Type = IntegerType::get(builder.getContext(), 64); |
188 | auto global = builder.createGlobal( |
189 | loc, i64Type, "global1" , builder.createInternalLinkage(), {}, true); |
190 | EXPECT_TRUE(mlir::isa<fir::GlobalOp>(global)); |
191 | EXPECT_EQ("global1" , global.getSymName()); |
192 | EXPECT_TRUE(global.getConstant().has_value()); |
193 | EXPECT_EQ(i64Type, global.getType()); |
194 | EXPECT_TRUE(global.getLinkName().has_value()); |
195 | EXPECT_EQ( |
196 | builder.createInternalLinkage().getValue(), global.getLinkName().value()); |
197 | EXPECT_FALSE(global.getInitVal().has_value()); |
198 | |
199 | auto g1 = builder.getNamedGlobal("global1" ); |
200 | EXPECT_EQ(global, g1); |
201 | auto g2 = builder.getNamedGlobal("global7" ); |
202 | EXPECT_EQ(nullptr, g2); |
203 | auto g3 = builder.getNamedGlobal("" ); |
204 | EXPECT_EQ(nullptr, g3); |
205 | } |
206 | |
207 | TEST_F(FIRBuilderTest, createGlobal2) { |
208 | auto builder = getBuilder(); |
209 | auto loc = builder.getUnknownLoc(); |
210 | auto i32Type = IntegerType::get(builder.getContext(), 32); |
211 | auto attr = builder.getIntegerAttr(i32Type, 16); |
212 | auto global = builder.createGlobal( |
213 | loc, i32Type, "global2" , builder.createLinkOnceLinkage(), attr, false); |
214 | EXPECT_TRUE(mlir::isa<fir::GlobalOp>(global)); |
215 | EXPECT_EQ("global2" , global.getSymName()); |
216 | EXPECT_FALSE(global.getConstant().has_value()); |
217 | EXPECT_EQ(i32Type, global.getType()); |
218 | EXPECT_TRUE(global.getInitVal().has_value()); |
219 | EXPECT_TRUE(global.getInitVal().value().isa<mlir::IntegerAttr>()); |
220 | EXPECT_EQ( |
221 | 16, global.getInitVal().value().cast<mlir::IntegerAttr>().getValue()); |
222 | EXPECT_TRUE(global.getLinkName().has_value()); |
223 | EXPECT_EQ( |
224 | builder.createLinkOnceLinkage().getValue(), global.getLinkName().value()); |
225 | } |
226 | |
227 | TEST_F(FIRBuilderTest, uniqueCFIdent) { |
228 | auto str1 = fir::factory::uniqueCGIdent("" , "func1" ); |
229 | EXPECT_EQ("_QQX66756E6331" , str1); |
230 | str1 = fir::factory::uniqueCGIdent("" , "" ); |
231 | EXPECT_EQ("_QQX" , str1); |
232 | str1 = fir::factory::uniqueCGIdent("pr" , "func1" ); |
233 | EXPECT_EQ("_QQprX66756E6331" , str1); |
234 | str1 = fir::factory::uniqueCGIdent( |
235 | "" , "longnamemorethan32characterneedshashing" ); |
236 | EXPECT_EQ("_QQXc22a886b2f30ea8c064ef1178377fc31" , str1); |
237 | str1 = fir::factory::uniqueCGIdent( |
238 | "pr" , "longnamemorethan32characterneedshashing" ); |
239 | EXPECT_EQ("_QQprXc22a886b2f30ea8c064ef1178377fc31" , str1); |
240 | } |
241 | |
242 | TEST_F(FIRBuilderTest, locationToLineNo) { |
243 | auto builder = getBuilder(); |
244 | auto loc = mlir::FileLineColLoc::get(builder.getStringAttr("file1" ), 10, 5); |
245 | mlir::Value line = |
246 | fir::factory::locationToLineNo(builder, loc, builder.getI64Type()); |
247 | checkIntegerConstant(line, builder.getI64Type(), 10); |
248 | line = fir::factory::locationToLineNo( |
249 | builder, builder.getUnknownLoc(), builder.getI64Type()); |
250 | checkIntegerConstant(line, builder.getI64Type(), 0); |
251 | } |
252 | |
253 | TEST_F(FIRBuilderTest, hasDynamicSize) { |
254 | auto builder = getBuilder(); |
255 | auto type = fir::CharacterType::get(builder.getContext(), 1, 16); |
256 | EXPECT_FALSE(fir::hasDynamicSize(type)); |
257 | EXPECT_TRUE(fir::SequenceType::getUnknownExtent()); |
258 | auto seqTy = builder.getVarLenSeqTy(builder.getI64Type(), 10); |
259 | EXPECT_TRUE(fir::hasDynamicSize(seqTy)); |
260 | EXPECT_FALSE(fir::hasDynamicSize(builder.getI64Type())); |
261 | } |
262 | |
263 | TEST_F(FIRBuilderTest, locationToFilename) { |
264 | auto builder = getBuilder(); |
265 | auto loc = |
266 | mlir::FileLineColLoc::get(builder.getStringAttr("file1.f90" ), 10, 5); |
267 | mlir::Value locToFile = fir::factory::locationToFilename(builder, loc); |
268 | auto addrOp = dyn_cast<fir::AddrOfOp>(locToFile.getDefiningOp()); |
269 | auto symbol = addrOp.getSymbol().getRootReference().getValue(); |
270 | auto global = builder.getNamedGlobal(symbol); |
271 | auto stringLitOps = global.getRegion().front().getOps<fir::StringLitOp>(); |
272 | EXPECT_TRUE(llvm::hasSingleElement(stringLitOps)); |
273 | for (auto stringLit : stringLitOps) { |
274 | EXPECT_EQ(10, stringLit.getSize().cast<mlir::IntegerAttr>().getValue()); |
275 | EXPECT_TRUE(stringLit.getValue().isa<StringAttr>()); |
276 | EXPECT_EQ(0, |
277 | strcmp("file1.f90\0" , |
278 | stringLit.getValue() |
279 | .dyn_cast<StringAttr>() |
280 | .getValue() |
281 | .str() |
282 | .c_str())); |
283 | } |
284 | } |
285 | |
286 | TEST_F(FIRBuilderTest, createStringLitOp) { |
287 | auto builder = getBuilder(); |
288 | llvm::StringRef data("mystringlitdata" ); |
289 | auto loc = builder.getUnknownLoc(); |
290 | auto op = builder.createStringLitOp(loc, data); |
291 | EXPECT_EQ(15, op.getSize().cast<mlir::IntegerAttr>().getValue()); |
292 | EXPECT_TRUE(op.getValue().isa<StringAttr>()); |
293 | EXPECT_EQ(data, op.getValue().dyn_cast<StringAttr>().getValue()); |
294 | } |
295 | |
296 | TEST_F(FIRBuilderTest, createStringLiteral) { |
297 | auto builder = getBuilder(); |
298 | auto loc = builder.getUnknownLoc(); |
299 | llvm::StringRef strValue("onestringliteral" ); |
300 | auto strLit = fir::factory::createStringLiteral(builder, loc, strValue); |
301 | EXPECT_EQ(0u, strLit.rank()); |
302 | EXPECT_TRUE(strLit.getCharBox() != nullptr); |
303 | auto *charBox = strLit.getCharBox(); |
304 | EXPECT_FALSE(fir::isArray(*charBox)); |
305 | checkIntegerConstant(charBox->getLen(), builder.getCharacterLengthType(), 16); |
306 | auto generalGetLen = fir::getLen(strLit); |
307 | checkIntegerConstant(generalGetLen, builder.getCharacterLengthType(), 16); |
308 | auto addr = charBox->getBuffer(); |
309 | EXPECT_TRUE(mlir::isa<fir::AddrOfOp>(addr.getDefiningOp())); |
310 | auto addrOp = dyn_cast<fir::AddrOfOp>(addr.getDefiningOp()); |
311 | auto symbol = addrOp.getSymbol().getRootReference().getValue(); |
312 | auto global = builder.getNamedGlobal(symbol); |
313 | EXPECT_EQ( |
314 | builder.createLinkOnceLinkage().getValue(), global.getLinkName().value()); |
315 | EXPECT_EQ(fir::CharacterType::get(builder.getContext(), 1, strValue.size()), |
316 | global.getType()); |
317 | |
318 | auto stringLitOps = global.getRegion().front().getOps<fir::StringLitOp>(); |
319 | EXPECT_TRUE(llvm::hasSingleElement(stringLitOps)); |
320 | for (auto stringLit : stringLitOps) { |
321 | EXPECT_EQ(16, stringLit.getSize().cast<mlir::IntegerAttr>().getValue()); |
322 | EXPECT_TRUE(stringLit.getValue().isa<StringAttr>()); |
323 | EXPECT_EQ(strValue, stringLit.getValue().dyn_cast<StringAttr>().getValue()); |
324 | } |
325 | } |
326 | |
327 | TEST_F(FIRBuilderTest, allocateLocal) { |
328 | auto builder = getBuilder(); |
329 | auto loc = builder.getUnknownLoc(); |
330 | llvm::StringRef varName = "var1" ; |
331 | auto var = builder.allocateLocal( |
332 | loc, builder.getI64Type(), "" , varName, {}, {}, false); |
333 | EXPECT_TRUE(mlir::isa<fir::AllocaOp>(var.getDefiningOp())); |
334 | auto allocaOp = dyn_cast<fir::AllocaOp>(var.getDefiningOp()); |
335 | EXPECT_EQ(builder.getI64Type(), allocaOp.getInType()); |
336 | EXPECT_TRUE(allocaOp.getBindcName().has_value()); |
337 | EXPECT_EQ(varName, allocaOp.getBindcName().value()); |
338 | EXPECT_FALSE(allocaOp.getUniqName().has_value()); |
339 | EXPECT_FALSE(allocaOp.getPinned()); |
340 | EXPECT_EQ(0u, allocaOp.getTypeparams().size()); |
341 | EXPECT_EQ(0u, allocaOp.getShape().size()); |
342 | } |
343 | |
344 | static void checkShapeOp(mlir::Value shape, mlir::Value c10, mlir::Value c100) { |
345 | EXPECT_TRUE(mlir::isa<fir::ShapeOp>(shape.getDefiningOp())); |
346 | fir::ShapeOp op = dyn_cast<fir::ShapeOp>(shape.getDefiningOp()); |
347 | auto shapeTy = op.getType().dyn_cast<fir::ShapeType>(); |
348 | EXPECT_EQ(2u, shapeTy.getRank()); |
349 | EXPECT_EQ(2u, op.getExtents().size()); |
350 | EXPECT_EQ(c10, op.getExtents()[0]); |
351 | EXPECT_EQ(c100, op.getExtents()[1]); |
352 | } |
353 | |
354 | TEST_F(FIRBuilderTest, genShapeWithExtents) { |
355 | auto builder = getBuilder(); |
356 | auto loc = builder.getUnknownLoc(); |
357 | auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10); |
358 | auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100); |
359 | llvm::SmallVector<mlir::Value> extents = {c10, c100}; |
360 | auto shape = builder.genShape(loc, extents); |
361 | checkShapeOp(shape, c10, c100); |
362 | } |
363 | |
364 | TEST_F(FIRBuilderTest, genShapeWithExtentsAndShapeShift) { |
365 | auto builder = getBuilder(); |
366 | auto loc = builder.getUnknownLoc(); |
367 | auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10); |
368 | auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100); |
369 | auto c1 = builder.createIntegerConstant(loc, builder.getI64Type(), 100); |
370 | llvm::SmallVector<mlir::Value> shifts = {c1, c1}; |
371 | llvm::SmallVector<mlir::Value> extents = {c10, c100}; |
372 | auto shape = builder.genShape(loc, shifts, extents); |
373 | EXPECT_TRUE(mlir::isa<fir::ShapeShiftOp>(shape.getDefiningOp())); |
374 | fir::ShapeShiftOp op = dyn_cast<fir::ShapeShiftOp>(shape.getDefiningOp()); |
375 | auto shapeTy = op.getType().dyn_cast<fir::ShapeShiftType>(); |
376 | EXPECT_EQ(2u, shapeTy.getRank()); |
377 | EXPECT_EQ(2u, op.getExtents().size()); |
378 | EXPECT_EQ(2u, op.getOrigins().size()); |
379 | } |
380 | |
381 | TEST_F(FIRBuilderTest, genShapeWithAbstractArrayBox) { |
382 | auto builder = getBuilder(); |
383 | auto loc = builder.getUnknownLoc(); |
384 | auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10); |
385 | auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100); |
386 | llvm::SmallVector<mlir::Value> extents = {c10, c100}; |
387 | fir::AbstractArrayBox aab(extents, {}); |
388 | EXPECT_TRUE(aab.lboundsAllOne()); |
389 | auto shape = builder.genShape(loc, aab); |
390 | checkShapeOp(shape, c10, c100); |
391 | } |
392 | |
393 | TEST_F(FIRBuilderTest, readCharLen) { |
394 | auto builder = getBuilder(); |
395 | auto loc = builder.getUnknownLoc(); |
396 | llvm::StringRef strValue("length" ); |
397 | auto strLit = fir::factory::createStringLiteral(builder, loc, strValue); |
398 | auto len = fir::factory::readCharLen(builder, loc, strLit); |
399 | EXPECT_EQ(strLit.getCharBox()->getLen(), len); |
400 | } |
401 | |
402 | TEST_F(FIRBuilderTest, getExtents) { |
403 | auto builder = getBuilder(); |
404 | auto loc = builder.getUnknownLoc(); |
405 | llvm::StringRef strValue("length" ); |
406 | auto strLit = fir::factory::createStringLiteral(builder, loc, strValue); |
407 | auto ext = fir::factory::getExtents(loc, builder, strLit); |
408 | EXPECT_EQ(0u, ext.size()); |
409 | auto c10 = builder.createIntegerConstant(loc, builder.getI64Type(), 10); |
410 | auto c100 = builder.createIntegerConstant(loc, builder.getI64Type(), 100); |
411 | llvm::SmallVector<mlir::Value> extents = {c10, c100}; |
412 | fir::SequenceType::Shape shape(2, fir::SequenceType::getUnknownExtent()); |
413 | auto arrayTy = fir::SequenceType::get(shape, builder.getI64Type()); |
414 | mlir::Value array = builder.create<fir::UndefOp>(loc, arrayTy); |
415 | fir::ArrayBoxValue aab(array, extents, {}); |
416 | fir::ExtendedValue ex(aab); |
417 | auto readExtents = fir::factory::getExtents(loc, builder, ex); |
418 | EXPECT_EQ(2u, readExtents.size()); |
419 | } |
420 | |
421 | TEST_F(FIRBuilderTest, createZeroValue) { |
422 | auto builder = getBuilder(); |
423 | auto loc = builder.getUnknownLoc(); |
424 | |
425 | mlir::Type i64Ty = mlir::IntegerType::get(builder.getContext(), 64); |
426 | mlir::Value zeroInt = fir::factory::createZeroValue(builder, loc, i64Ty); |
427 | EXPECT_TRUE(zeroInt.getType() == i64Ty); |
428 | auto cst = |
429 | mlir::dyn_cast_or_null<mlir::arith::ConstantOp>(zeroInt.getDefiningOp()); |
430 | EXPECT_TRUE(cst); |
431 | auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>(); |
432 | EXPECT_TRUE(intAttr && intAttr.getInt() == 0); |
433 | |
434 | mlir::Type f32Ty = mlir::FloatType::getF32(builder.getContext()); |
435 | mlir::Value zeroFloat = fir::factory::createZeroValue(builder, loc, f32Ty); |
436 | EXPECT_TRUE(zeroFloat.getType() == f32Ty); |
437 | auto cst2 = mlir::dyn_cast_or_null<mlir::arith::ConstantOp>( |
438 | zeroFloat.getDefiningOp()); |
439 | EXPECT_TRUE(cst2); |
440 | auto floatAttr = cst2.getValue().dyn_cast<mlir::FloatAttr>(); |
441 | EXPECT_TRUE(floatAttr && floatAttr.getValueAsDouble() == 0.); |
442 | |
443 | mlir::Type boolTy = mlir::IntegerType::get(builder.getContext(), 1); |
444 | mlir::Value flaseBool = fir::factory::createZeroValue(builder, loc, boolTy); |
445 | EXPECT_TRUE(flaseBool.getType() == boolTy); |
446 | auto cst3 = mlir::dyn_cast_or_null<mlir::arith::ConstantOp>( |
447 | flaseBool.getDefiningOp()); |
448 | EXPECT_TRUE(cst3); |
449 | auto intAttr2 = cst.getValue().dyn_cast<mlir::IntegerAttr>(); |
450 | EXPECT_TRUE(intAttr2 && intAttr2.getInt() == 0); |
451 | } |
452 | |
453 | TEST_F(FIRBuilderTest, getBaseTypeOf) { |
454 | auto builder = getBuilder(); |
455 | auto loc = builder.getUnknownLoc(); |
456 | |
457 | auto makeExv = [&](mlir::Type elementType, mlir::Type arrayType) |
458 | -> std::tuple<llvm::SmallVector<fir::ExtendedValue, 4>, |
459 | llvm::SmallVector<fir::ExtendedValue, 4>> { |
460 | auto ptrTyArray = fir::PointerType::get(arrayType); |
461 | auto ptrTyScalar = fir::PointerType::get(elementType); |
462 | auto ptrBoxTyArray = fir::BoxType::get(ptrTyArray); |
463 | auto ptrBoxTyScalar = fir::BoxType::get(ptrTyScalar); |
464 | auto boxRefTyArray = fir::ReferenceType::get(ptrBoxTyArray); |
465 | auto boxRefTyScalar = fir::ReferenceType::get(ptrBoxTyScalar); |
466 | auto boxTyArray = fir::BoxType::get(arrayType); |
467 | auto boxTyScalar = fir::BoxType::get(elementType); |
468 | |
469 | auto ptrValArray = builder.create<fir::UndefOp>(loc, ptrTyArray); |
470 | auto ptrValScalar = builder.create<fir::UndefOp>(loc, ptrTyScalar); |
471 | auto boxRefValArray = builder.create<fir::UndefOp>(loc, boxRefTyArray); |
472 | auto boxRefValScalar = builder.create<fir::UndefOp>(loc, boxRefTyScalar); |
473 | auto boxValArray = builder.create<fir::UndefOp>(loc, boxTyArray); |
474 | auto boxValScalar = builder.create<fir::UndefOp>(loc, boxTyScalar); |
475 | |
476 | llvm::SmallVector<fir::ExtendedValue, 4> scalars; |
477 | scalars.emplace_back(fir::UnboxedValue(ptrValScalar)); |
478 | scalars.emplace_back(fir::BoxValue(boxValScalar)); |
479 | scalars.emplace_back( |
480 | fir::MutableBoxValue(boxRefValScalar, mlir::ValueRange(), {})); |
481 | |
482 | llvm::SmallVector<fir::ExtendedValue, 4> arrays; |
483 | auto extent = builder.create<fir::UndefOp>(loc, builder.getIndexType()); |
484 | llvm::SmallVector<mlir::Value> extents( |
485 | arrayType.dyn_cast<fir::SequenceType>().getDimension(), |
486 | extent.getResult()); |
487 | arrays.emplace_back(fir::ArrayBoxValue(ptrValArray, extents)); |
488 | arrays.emplace_back(fir::BoxValue(boxValArray)); |
489 | arrays.emplace_back( |
490 | fir::MutableBoxValue(boxRefValArray, mlir::ValueRange(), {})); |
491 | return {scalars, arrays}; |
492 | }; |
493 | |
494 | auto f32Ty = mlir::FloatType::getF32(builder.getContext()); |
495 | mlir::Type f32SeqTy = builder.getVarLenSeqTy(f32Ty); |
496 | auto [f32Scalars, f32Arrays] = makeExv(f32Ty, f32SeqTy); |
497 | for (const auto &scalar : f32Scalars) { |
498 | EXPECT_EQ(fir::getBaseTypeOf(scalar), f32Ty); |
499 | EXPECT_EQ(fir::getElementTypeOf(scalar), f32Ty); |
500 | EXPECT_FALSE(fir::isDerivedWithLenParameters(scalar)); |
501 | } |
502 | for (const auto &array : f32Arrays) { |
503 | EXPECT_EQ(fir::getBaseTypeOf(array), f32SeqTy); |
504 | EXPECT_EQ(fir::getElementTypeOf(array), f32Ty); |
505 | EXPECT_FALSE(fir::isDerivedWithLenParameters(array)); |
506 | } |
507 | |
508 | auto derivedWithLengthTy = |
509 | fir::RecordType::get(builder.getContext(), "derived_test" ); |
510 | |
511 | llvm::SmallVector<std::pair<std::string, mlir::Type>> parameters; |
512 | llvm::SmallVector<std::pair<std::string, mlir::Type>> components; |
513 | parameters.emplace_back("p1" , builder.getI64Type()); |
514 | components.emplace_back("c1" , f32Ty); |
515 | derivedWithLengthTy.finalize(parameters, components); |
516 | mlir::Type derivedWithLengthSeqTy = |
517 | builder.getVarLenSeqTy(derivedWithLengthTy); |
518 | auto [derivedWithLengthScalars, derivedWithLengthArrays] = |
519 | makeExv(derivedWithLengthTy, derivedWithLengthSeqTy); |
520 | for (const auto &scalar : derivedWithLengthScalars) { |
521 | EXPECT_EQ(fir::getBaseTypeOf(scalar), derivedWithLengthTy); |
522 | EXPECT_EQ(fir::getElementTypeOf(scalar), derivedWithLengthTy); |
523 | EXPECT_TRUE(fir::isDerivedWithLenParameters(scalar)); |
524 | } |
525 | for (const auto &array : derivedWithLengthArrays) { |
526 | EXPECT_EQ(fir::getBaseTypeOf(array), derivedWithLengthSeqTy); |
527 | EXPECT_EQ(fir::getElementTypeOf(array), derivedWithLengthTy); |
528 | EXPECT_TRUE(fir::isDerivedWithLenParameters(array)); |
529 | } |
530 | } |
531 | |
532 | TEST_F(FIRBuilderTest, genArithFastMath) { |
533 | auto builder = getBuilder(); |
534 | auto ctx = builder.getContext(); |
535 | auto loc = builder.getUnknownLoc(); |
536 | |
537 | auto realTy = mlir::FloatType::getF32(ctx); |
538 | auto arg = builder.create<fir::UndefOp>(loc, realTy); |
539 | |
540 | // Test that FastMathFlags is 'none' by default. |
541 | mlir::Operation *op1 = builder.create<mlir::arith::AddFOp>(loc, arg, arg); |
542 | auto op1_fmi = |
543 | mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op1); |
544 | EXPECT_TRUE(op1_fmi); |
545 | auto op1_fmf = op1_fmi.getFastMathFlagsAttr().getValue(); |
546 | EXPECT_EQ(op1_fmf, arith::FastMathFlags::none); |
547 | |
548 | // Test that the builder is copied properly. |
549 | fir::FirOpBuilder builder_copy(builder); |
550 | |
551 | arith::FastMathFlags FMF1 = |
552 | arith::FastMathFlags::contract | arith::FastMathFlags::reassoc; |
553 | builder.setFastMathFlags(FMF1); |
554 | arith::FastMathFlags FMF2 = |
555 | arith::FastMathFlags::nnan | arith::FastMathFlags::ninf; |
556 | builder_copy.setFastMathFlags(FMF2); |
557 | |
558 | // Modifying FastMathFlags for the copy must not affect the original builder. |
559 | mlir::Operation *op2 = builder.create<mlir::arith::AddFOp>(loc, arg, arg); |
560 | auto op2_fmi = |
561 | mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op2); |
562 | EXPECT_TRUE(op2_fmi); |
563 | auto op2_fmf = op2_fmi.getFastMathFlagsAttr().getValue(); |
564 | EXPECT_EQ(op2_fmf, FMF1); |
565 | |
566 | // Modifying FastMathFlags for the original builder must not affect the copy. |
567 | mlir::Operation *op3 = |
568 | builder_copy.create<mlir::arith::AddFOp>(loc, arg, arg); |
569 | auto op3_fmi = |
570 | mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op3); |
571 | EXPECT_TRUE(op3_fmi); |
572 | auto op3_fmf = op3_fmi.getFastMathFlagsAttr().getValue(); |
573 | EXPECT_EQ(op3_fmf, FMF2); |
574 | |
575 | // Test that the builder copy inherits FastMathFlags from the original. |
576 | fir::FirOpBuilder builder_copy2(builder); |
577 | |
578 | mlir::Operation *op4 = |
579 | builder_copy2.create<mlir::arith::AddFOp>(loc, arg, arg); |
580 | auto op4_fmi = |
581 | mlir::dyn_cast_or_null<mlir::arith::ArithFastMathInterface>(op4); |
582 | EXPECT_TRUE(op4_fmi); |
583 | auto op4_fmf = op4_fmi.getFastMathFlagsAttr().getValue(); |
584 | EXPECT_EQ(op4_fmf, FMF1); |
585 | } |
586 | |