1 //===- HLFIRToolsTest.cpp -- HLFIR tools unit tests -----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Optimizer/Builder/HLFIRTools.h"
10 #include "gtest/gtest.h"
11 #include "flang/Optimizer/Builder/BoxValue.h"
12 #include "flang/Optimizer/Builder/FIRBuilder.h"
13 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
14 #include "flang/Optimizer/Support/InitFIR.h"
16 struct HLFIRToolsTest
: public testing::Test
{
18 void SetUp() override
{
19 fir::support::loadDialects(context
);
21 llvm::ArrayRef
<fir::KindTy
> defs
;
22 fir::KindMapping
kindMap(&context
, defs
);
23 mlir::OpBuilder
builder(&context
);
24 auto loc
= builder
.getUnknownLoc();
26 // Set up a Module with a dummy function operation inside.
27 // Set the insertion point in the function entry block.
28 moduleOp
= builder
.create
<mlir::ModuleOp
>(loc
);
29 builder
.setInsertionPointToStart(moduleOp
->getBody());
30 mlir::func::FuncOp func
= builder
.create
<mlir::func::FuncOp
>(
31 loc
, "func1", builder
.getFunctionType(std::nullopt
, std::nullopt
));
32 auto *entryBlock
= func
.addEntryBlock();
33 builder
.setInsertionPointToStart(entryBlock
);
35 firBuilder
= std::make_unique
<fir::FirOpBuilder
>(builder
, kindMap
);
38 mlir::Value
createDeclare(fir::ExtendedValue exv
) {
39 return hlfir::genDeclare(getLoc(), *firBuilder
, exv
,
40 "x" + std::to_string(varCounter
++), fir::FortranVariableFlagsAttr
{})
44 mlir::Value
createConstant(std::int64_t cst
) {
45 mlir::Type indexType
= firBuilder
->getIndexType();
46 return firBuilder
->create
<mlir::arith::ConstantOp
>(
47 getLoc(), indexType
, firBuilder
->getIntegerAttr(indexType
, cst
));
50 mlir::Location
getLoc() { return firBuilder
->getUnknownLoc(); }
51 fir::FirOpBuilder
&getBuilder() { return *firBuilder
; }
54 mlir::MLIRContext context
;
55 mlir::OwningOpRef
<mlir::ModuleOp
> moduleOp
;
56 std::unique_ptr
<fir::FirOpBuilder
> firBuilder
;
59 TEST_F(HLFIRToolsTest
, testScalarRoundTrip
) {
60 auto &builder
= getBuilder();
61 mlir::Location loc
= getLoc();
62 mlir::Type f32Type
= mlir::FloatType::getF32(&context
);
63 mlir::Type scalarf32Type
= builder
.getRefType(f32Type
);
64 mlir::Value scalarf32Addr
= builder
.create
<fir::UndefOp
>(loc
, scalarf32Type
);
65 fir::ExtendedValue scalarf32
{scalarf32Addr
};
66 hlfir::EntityWithAttributes
scalarf32Entity(createDeclare(scalarf32
));
67 auto [scalarf32Result
, cleanup
] =
68 hlfir::translateToExtendedValue(loc
, builder
, scalarf32Entity
);
69 auto *unboxed
= scalarf32Result
.getUnboxed();
70 EXPECT_FALSE(cleanup
.has_value());
71 ASSERT_NE(unboxed
, nullptr);
72 EXPECT_TRUE(*unboxed
== scalarf32Entity
.getFirBase());
73 EXPECT_TRUE(scalarf32Entity
.isVariable());
74 EXPECT_FALSE(scalarf32Entity
.isValue());
77 TEST_F(HLFIRToolsTest
, testArrayRoundTrip
) {
78 auto &builder
= getBuilder();
79 mlir::Location loc
= getLoc();
80 llvm::SmallVector
<mlir::Value
> extents
{
81 createConstant(20), createConstant(30)};
82 llvm::SmallVector
<mlir::Value
> lbounds
{
83 createConstant(-1), createConstant(-2)};
85 mlir::Type f32Type
= mlir::FloatType::getF32(&context
);
86 mlir::Type seqf32Type
= builder
.getVarLenSeqTy(f32Type
, 2);
87 mlir::Type arrayf32Type
= builder
.getRefType(seqf32Type
);
88 mlir::Value arrayf32Addr
= builder
.create
<fir::UndefOp
>(loc
, arrayf32Type
);
89 fir::ArrayBoxValue arrayf32
{arrayf32Addr
, extents
, lbounds
};
90 hlfir::EntityWithAttributes
arrayf32Entity(createDeclare(arrayf32
));
91 auto [arrayf32Result
, cleanup
] =
92 hlfir::translateToExtendedValue(loc
, builder
, arrayf32Entity
);
93 auto *res
= arrayf32Result
.getBoxOf
<fir::ArrayBoxValue
>();
94 EXPECT_FALSE(cleanup
.has_value());
95 ASSERT_NE(res
, nullptr);
96 // gtest has a terrible time printing mlir::Value in case of failing
97 // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead.
98 EXPECT_TRUE(fir::getBase(*res
) == arrayf32Entity
.getFirBase());
99 ASSERT_EQ(res
->getExtents().size(), arrayf32
.getExtents().size());
100 for (unsigned i
= 0; i
< arrayf32
.getExtents().size(); ++i
)
101 EXPECT_TRUE(res
->getExtents()[i
] == arrayf32
.getExtents()[i
]);
102 ASSERT_EQ(res
->getLBounds().size(), arrayf32
.getLBounds().size());
103 for (unsigned i
= 0; i
< arrayf32
.getLBounds().size(); ++i
)
104 EXPECT_TRUE(res
->getLBounds()[i
] == arrayf32
.getLBounds()[i
]);
105 EXPECT_TRUE(arrayf32Entity
.isVariable());
106 EXPECT_FALSE(arrayf32Entity
.isValue());
109 TEST_F(HLFIRToolsTest
, testScalarCharRoundTrip
) {
110 auto &builder
= getBuilder();
111 mlir::Location loc
= getLoc();
112 mlir::Value len
= createConstant(42);
113 mlir::Type charType
= fir::CharacterType::getUnknownLen(&context
, 1);
114 mlir::Type scalarCharType
= builder
.getRefType(charType
);
115 mlir::Value scalarCharAddr
=
116 builder
.create
<fir::UndefOp
>(loc
, scalarCharType
);
117 fir::CharBoxValue scalarChar
{scalarCharAddr
, len
};
118 hlfir::EntityWithAttributes
scalarCharEntity(createDeclare(scalarChar
));
119 auto [scalarCharResult
, cleanup
] =
120 hlfir::translateToExtendedValue(loc
, builder
, scalarCharEntity
);
121 auto *res
= scalarCharResult
.getBoxOf
<fir::CharBoxValue
>();
122 EXPECT_FALSE(cleanup
.has_value());
123 ASSERT_NE(res
, nullptr);
124 EXPECT_TRUE(fir::getBase(*res
) == scalarCharEntity
.getFirBase());
125 EXPECT_TRUE(res
->getLen() == scalarChar
.getLen());
126 EXPECT_TRUE(scalarCharEntity
.isVariable());
127 EXPECT_FALSE(scalarCharEntity
.isValue());
130 TEST_F(HLFIRToolsTest
, testArrayCharRoundTrip
) {
131 auto &builder
= getBuilder();
132 mlir::Location loc
= getLoc();
133 llvm::SmallVector
<mlir::Value
> extents
{
134 createConstant(20), createConstant(30)};
135 llvm::SmallVector
<mlir::Value
> lbounds
{
136 createConstant(-1), createConstant(-2)};
137 mlir::Value len
= createConstant(42);
138 mlir::Type charType
= fir::CharacterType::getUnknownLen(&context
, 1);
139 mlir::Type seqCharType
= builder
.getVarLenSeqTy(charType
, 2);
140 mlir::Type arrayCharType
= builder
.getRefType(seqCharType
);
141 mlir::Value arrayCharAddr
= builder
.create
<fir::UndefOp
>(loc
, arrayCharType
);
142 fir::CharArrayBoxValue arrayChar
{arrayCharAddr
, len
, extents
, lbounds
};
143 hlfir::EntityWithAttributes
arrayCharEntity(createDeclare(arrayChar
));
144 auto [arrayCharResult
, cleanup
] =
145 hlfir::translateToExtendedValue(loc
, builder
, arrayCharEntity
);
146 auto *res
= arrayCharResult
.getBoxOf
<fir::CharArrayBoxValue
>();
147 EXPECT_FALSE(cleanup
.has_value());
148 ASSERT_NE(res
, nullptr);
149 // gtest has a terrible time printing mlir::Value in case of failing
150 // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead.
151 EXPECT_TRUE(fir::getBase(*res
) == arrayCharEntity
.getFirBase());
152 EXPECT_TRUE(res
->getLen() == arrayChar
.getLen());
153 ASSERT_EQ(res
->getExtents().size(), arrayChar
.getExtents().size());
154 for (unsigned i
= 0; i
< arrayChar
.getExtents().size(); ++i
)
155 EXPECT_TRUE(res
->getExtents()[i
] == arrayChar
.getExtents()[i
]);
156 ASSERT_EQ(res
->getLBounds().size(), arrayChar
.getLBounds().size());
157 for (unsigned i
= 0; i
< arrayChar
.getLBounds().size(); ++i
)
158 EXPECT_TRUE(res
->getLBounds()[i
] == arrayChar
.getLBounds()[i
]);
159 EXPECT_TRUE(arrayCharEntity
.isVariable());
160 EXPECT_FALSE(arrayCharEntity
.isValue());
163 TEST_F(HLFIRToolsTest
, testArrayCharBoxRoundTrip
) {
164 auto &builder
= getBuilder();
165 mlir::Location loc
= getLoc();
166 llvm::SmallVector
<mlir::Value
> lbounds
{
167 createConstant(-1), createConstant(-2)};
168 mlir::Value len
= createConstant(42);
169 mlir::Type charType
= fir::CharacterType::getUnknownLen(&context
, 1);
170 mlir::Type seqCharType
= builder
.getVarLenSeqTy(charType
, 2);
171 mlir::Type arrayCharBoxType
= fir::BoxType::get(seqCharType
);
172 mlir::Value arrayCharAddr
=
173 builder
.create
<fir::UndefOp
>(loc
, arrayCharBoxType
);
174 llvm::SmallVector
<mlir::Value
> explicitTypeParams
{len
};
175 fir::BoxValue arrayChar
{arrayCharAddr
, lbounds
, explicitTypeParams
};
176 hlfir::EntityWithAttributes
arrayCharEntity(createDeclare(arrayChar
));
177 auto [arrayCharResult
, cleanup
] =
178 hlfir::translateToExtendedValue(loc
, builder
, arrayCharEntity
);
179 auto *res
= arrayCharResult
.getBoxOf
<fir::BoxValue
>();
180 EXPECT_FALSE(cleanup
.has_value());
181 ASSERT_NE(res
, nullptr);
182 // gtest has a terrible time printing mlir::Value in case of failing
183 // EXPECT_EQ(mlir::Value, mlir::Value). So use EXPECT_TRUE instead.
184 EXPECT_TRUE(fir::getBase(*res
) == arrayCharEntity
.getFirBase());
185 ASSERT_EQ(res
->getExplicitParameters().size(),
186 arrayChar
.getExplicitParameters().size());
187 for (unsigned i
= 0; i
< arrayChar
.getExplicitParameters().size(); ++i
)
188 EXPECT_TRUE(res
->getExplicitParameters()[i
] ==
189 arrayChar
.getExplicitParameters()[i
]);
190 ASSERT_EQ(res
->getLBounds().size(), arrayChar
.getLBounds().size());
191 for (unsigned i
= 0; i
< arrayChar
.getLBounds().size(); ++i
)
192 EXPECT_TRUE(res
->getLBounds()[i
] == arrayChar
.getLBounds()[i
]);
193 EXPECT_TRUE(arrayCharEntity
.isVariable());
194 EXPECT_FALSE(arrayCharEntity
.isValue());