Skip to content

Commit f17f694

Browse files
clementvaljeanPerierschweitzpgi
committed
[fir] Add IfBuilder and utility functions
In order to reduct the size of D111337. The IfBuilder and the two utility functions genIsNotNull and genIsNull have been extracted in a separate patch with dedicated unittests. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: Leporacanthicus Differential Revision: https://reviews.llvm.org/D111796 Co-authored-by: Jean Perier <[email protected]> Co-authored-by: Eric Schweitz <[email protected]>
1 parent dbf5dc8 commit f17f694

File tree

4 files changed

+197
-0
lines changed

4 files changed

+197
-0
lines changed

flang/include/flang/Optimizer/Builder/FIRBuilder.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ class FirOpBuilder : public mlir::OpBuilder {
3838
const fir::KindMapping &kindMap)
3939
: OpBuilder{builder} {}
4040

41+
/// Get the integer type whose bit width corresponds to the width of pointer
42+
/// types, or is bigger.
43+
mlir::Type getIntPtrType() {
44+
// TODO: Delay the need of such type until codegen or find a way to use
45+
// llvm::DataLayout::getPointerSizeInBits here.
46+
return getI64Type();
47+
}
48+
4149
/// Create an integer constant of type \p type and value \p i.
4250
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
4351
std::int64_t i);
@@ -50,6 +58,74 @@ class FirOpBuilder : public mlir::OpBuilder {
5058
mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
5159
return createConvert(loc, getIndexType(), val);
5260
}
61+
62+
//===--------------------------------------------------------------------===//
63+
// If-Then-Else generation helper
64+
//===--------------------------------------------------------------------===//
65+
66+
/// Helper class to create if-then-else in a structured way:
67+
/// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end();
68+
/// Alternatively, getResults() can be used instead of end() to end the ifOp
69+
/// and get the ifOp results.
70+
class IfBuilder {
71+
public:
72+
IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder)
73+
: ifOp{ifOp}, builder{builder} {}
74+
template <typename CC>
75+
IfBuilder &genThen(CC func) {
76+
builder.setInsertionPointToStart(&ifOp.thenRegion().front());
77+
func();
78+
return *this;
79+
}
80+
template <typename CC>
81+
IfBuilder &genElse(CC func) {
82+
assert(!ifOp.elseRegion().empty() && "must have else region");
83+
builder.setInsertionPointToStart(&ifOp.elseRegion().front());
84+
func();
85+
return *this;
86+
}
87+
void end() { builder.setInsertionPointAfter(ifOp); }
88+
89+
/// End the IfOp and return the results if any.
90+
mlir::Operation::result_range getResults() {
91+
end();
92+
return ifOp.getResults();
93+
}
94+
95+
fir::IfOp &getIfOp() { return ifOp; };
96+
97+
private:
98+
fir::IfOp ifOp;
99+
FirOpBuilder &builder;
100+
};
101+
102+
/// Create an IfOp and returns an IfBuilder that can generate the else/then
103+
/// bodies.
104+
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results,
105+
mlir::Value cdt, bool withElseRegion) {
106+
auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion);
107+
return IfBuilder(op, *this);
108+
}
109+
110+
/// Create an IfOp with no "else" region, and no result values.
111+
/// Usage: genIfThen(loc, cdt).genThen(lambda).end();
112+
IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) {
113+
auto op = create<fir::IfOp>(loc, llvm::None, cdt, false);
114+
return IfBuilder(op, *this);
115+
}
116+
117+
/// Create an IfOp with an "else" region, and no result values.
118+
/// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end();
119+
IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) {
120+
auto op = create<fir::IfOp>(loc, llvm::None, cdt, true);
121+
return IfBuilder(op, *this);
122+
}
123+
124+
/// Generate code testing \p addr is not a null address.
125+
mlir::Value genIsNotNull(mlir::Location loc, mlir::Value addr);
126+
127+
/// Generate code testing \p addr is a null address.
128+
mlir::Value genIsNull(mlir::Location loc, mlir::Value addr);
53129
};
54130

55131
} // namespace fir

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,22 @@ mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc,
2222
}
2323
return val;
2424
}
25+
26+
static mlir::Value genNullPointerComparison(fir::FirOpBuilder &builder,
27+
mlir::Location loc,
28+
mlir::Value addr,
29+
arith::CmpIPredicate condition) {
30+
auto intPtrTy = builder.getIntPtrType();
31+
auto ptrToInt = builder.createConvert(loc, intPtrTy, addr);
32+
auto c0 = builder.createIntegerConstant(loc, intPtrTy, 0);
33+
return builder.create<arith::CmpIOp>(loc, condition, ptrToInt, c0);
34+
}
35+
36+
mlir::Value fir::FirOpBuilder::genIsNotNull(mlir::Location loc,
37+
mlir::Value addr) {
38+
return genNullPointerComparison(*this, loc, addr, arith::CmpIPredicate::ne);
39+
}
40+
41+
mlir::Value fir::FirOpBuilder::genIsNull(mlir::Location loc, mlir::Value addr) {
42+
return genNullPointerComparison(*this, loc, addr, arith::CmpIPredicate::eq);
43+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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/Support/InitFIR.h"
12+
#include "flang/Optimizer/Support/KindMapping.h"
13+
14+
struct FIRBuilderTest : public testing::Test {
15+
public:
16+
void SetUp() override {
17+
fir::KindMapping kindMap(&context);
18+
mlir::OpBuilder builder(&context);
19+
firBuilder = std::make_unique<fir::FirOpBuilder>(builder, kindMap);
20+
fir::support::loadDialects(context);
21+
}
22+
23+
fir::FirOpBuilder &getBuilder() { return *firBuilder; }
24+
25+
mlir::MLIRContext context;
26+
std::unique_ptr<fir::FirOpBuilder> firBuilder;
27+
};
28+
29+
static arith::CmpIOp createCondition(fir::FirOpBuilder &builder) {
30+
auto loc = builder.getUnknownLoc();
31+
auto zero1 = builder.createIntegerConstant(loc, builder.getIndexType(), 0);
32+
auto zero2 = builder.createIntegerConstant(loc, builder.getIndexType(), 0);
33+
return builder.create<arith::CmpIOp>(
34+
loc, arith::CmpIPredicate::eq, zero1, zero2);
35+
}
36+
37+
//===----------------------------------------------------------------------===//
38+
// IfBuilder tests
39+
//===----------------------------------------------------------------------===//
40+
41+
TEST_F(FIRBuilderTest, genIfThen) {
42+
auto builder = getBuilder();
43+
auto loc = builder.getUnknownLoc();
44+
auto cdt = createCondition(builder);
45+
auto ifBuilder = builder.genIfThen(loc, cdt);
46+
EXPECT_FALSE(ifBuilder.getIfOp().thenRegion().empty());
47+
EXPECT_TRUE(ifBuilder.getIfOp().elseRegion().empty());
48+
}
49+
50+
TEST_F(FIRBuilderTest, genIfThenElse) {
51+
auto builder = getBuilder();
52+
auto loc = builder.getUnknownLoc();
53+
auto cdt = createCondition(builder);
54+
auto ifBuilder = builder.genIfThenElse(loc, cdt);
55+
EXPECT_FALSE(ifBuilder.getIfOp().thenRegion().empty());
56+
EXPECT_FALSE(ifBuilder.getIfOp().elseRegion().empty());
57+
}
58+
59+
TEST_F(FIRBuilderTest, genIfWithThen) {
60+
auto builder = getBuilder();
61+
auto loc = builder.getUnknownLoc();
62+
auto cdt = createCondition(builder);
63+
auto ifBuilder = builder.genIfOp(loc, {}, cdt, false);
64+
EXPECT_FALSE(ifBuilder.getIfOp().thenRegion().empty());
65+
EXPECT_TRUE(ifBuilder.getIfOp().elseRegion().empty());
66+
}
67+
68+
TEST_F(FIRBuilderTest, genIfWithThenAndElse) {
69+
auto builder = getBuilder();
70+
auto loc = builder.getUnknownLoc();
71+
auto cdt = createCondition(builder);
72+
auto ifBuilder = builder.genIfOp(loc, {}, cdt, true);
73+
EXPECT_FALSE(ifBuilder.getIfOp().thenRegion().empty());
74+
EXPECT_FALSE(ifBuilder.getIfOp().elseRegion().empty());
75+
}
76+
77+
//===----------------------------------------------------------------------===//
78+
// Helper functions tests
79+
//===----------------------------------------------------------------------===//
80+
81+
TEST_F(FIRBuilderTest, genIsNotNull) {
82+
auto builder = getBuilder();
83+
auto loc = builder.getUnknownLoc();
84+
auto dummyValue =
85+
builder.createIntegerConstant(loc, builder.getIndexType(), 0);
86+
auto res = builder.genIsNotNull(loc, dummyValue);
87+
EXPECT_TRUE(mlir::isa<arith::CmpIOp>(res.getDefiningOp()));
88+
auto cmpOp = dyn_cast<arith::CmpIOp>(res.getDefiningOp());
89+
EXPECT_EQ(arith::CmpIPredicate::ne, cmpOp.predicate());
90+
}
91+
92+
TEST_F(FIRBuilderTest, genIsNull) {
93+
auto builder = getBuilder();
94+
auto loc = builder.getUnknownLoc();
95+
auto dummyValue =
96+
builder.createIntegerConstant(loc, builder.getIndexType(), 0);
97+
auto res = builder.genIsNull(loc, dummyValue);
98+
EXPECT_TRUE(mlir::isa<arith::CmpIOp>(res.getDefiningOp()));
99+
auto cmpOp = dyn_cast<arith::CmpIOp>(res.getDefiningOp());
100+
EXPECT_EQ(arith::CmpIPredicate::eq, cmpOp.predicate());
101+
}

flang/unittests/Optimizer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(LIBS
1010

1111
add_flang_unittest(FlangOptimizerTests
1212
Builder/DoLoopHelperTest.cpp
13+
Builder/FIRBuilderTest.cpp
1314
FIRContextTest.cpp
1415
InternalNamesTest.cpp
1516
KindMappingTest.cpp

0 commit comments

Comments
 (0)