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