xref: /llvm-project/flang/unittests/Optimizer/Builder/FIRBuilderTest.cpp (revision f023da12d12635f5fba436e825cbfc999e28e623)
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