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
15using namespace mlir;
16
17struct FIRBuilderTest : public testing::Test {
18public:
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
46static 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
54static 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
66TEST_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
75TEST_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
84TEST_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
93TEST_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
106TEST_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
117TEST_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
128TEST_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
145TEST_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
158TEST_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
165TEST_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
174TEST_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
185TEST_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
208TEST_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
228TEST_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
243TEST_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
254TEST_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
264TEST_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
287TEST_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
297TEST_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
330TEST_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
347static 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
357TEST_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
367TEST_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
384TEST_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
396TEST_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
405TEST_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
424TEST_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
456TEST_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
535TEST_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
590TEST_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

source code of flang/unittests/Optimizer/Builder/FIRBuilderTest.cpp