Skip to content
This repository was archived by the owner on Jan 26, 2024. It is now read-only.

Commit 45503fc

Browse files
clementvaljeanPerierschweitzpgi
committed
[fir] Add FIRBuilder utility functions
Extract some code from the big ptach D111337. This patch contains some utility functions from the FIRBuidler. List of utility functions added: - getRegion - getModule - getKindMap - getRefType - getVarLenSeqTy - getRealType - createNullConstant - createRealConstant - createRealZeroConstant - createGlobal - createGlobalConstant - createStringLitOp - getNamedFunction - getNamedGlobal - createFunction - addNamedFunction - createBool This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D112057 Co-authored-by: Jean Perier <[email protected]> Co-authored-by: Eric Schweitz <[email protected]>
1 parent d576f45 commit 45503fc

File tree

4 files changed

+477
-7
lines changed

4 files changed

+477
-7
lines changed

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

+158-5
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,27 @@ namespace fir {
3333
class FirOpBuilder : public mlir::OpBuilder {
3434
public:
3535
explicit FirOpBuilder(mlir::Operation *op, const fir::KindMapping &kindMap)
36-
: OpBuilder{op} {}
36+
: OpBuilder{op}, kindMap{kindMap} {}
3737
explicit FirOpBuilder(mlir::OpBuilder &builder,
3838
const fir::KindMapping &kindMap)
39-
: OpBuilder{builder} {}
39+
: OpBuilder{builder}, kindMap{kindMap} {}
40+
41+
/// Get the current Region of the insertion point.
42+
mlir::Region &getRegion() { return *getBlock()->getParent(); }
43+
44+
/// Get the current Module
45+
mlir::ModuleOp getModule() {
46+
return getRegion().getParentOfType<mlir::ModuleOp>();
47+
}
48+
49+
/// Get a reference to the kind map.
50+
const fir::KindMapping &getKindMap() { return kindMap; }
51+
52+
/// Safely create a reference type to the type `eleTy`.
53+
mlir::Type getRefType(mlir::Type eleTy);
54+
55+
/// Create a sequence of `eleTy` with `rank` dimensions of unknown size.
56+
mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1);
4057

4158
/// Get the integer type whose bit width corresponds to the width of pointer
4259
/// types, or is bigger.
@@ -46,19 +63,133 @@ class FirOpBuilder : public mlir::OpBuilder {
4663
return getI64Type();
4764
}
4865

66+
/// Get the mlir real type that implements fortran REAL(kind).
67+
mlir::Type getRealType(int kind);
68+
69+
/// Create a null constant memory reference of type \p ptrType.
70+
/// If \p ptrType is not provided, !fir.ref<none> type will be used.
71+
mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {});
72+
4973
/// Create an integer constant of type \p type and value \p i.
5074
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
5175
std::int64_t i);
5276

53-
/// Lazy creation of fir.convert op.
54-
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
55-
mlir::Value val);
77+
/// Create a real constant from an integer value.
78+
mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
79+
llvm::APFloat::integerPart val);
80+
81+
/// Create a real constant from an APFloat value.
82+
mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
83+
const llvm::APFloat &val);
84+
85+
/// Create a real constant of type \p realType with a value zero.
86+
mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) {
87+
return createRealConstant(loc, realType, 0u);
88+
}
89+
90+
/// Create a global value.
91+
fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
92+
llvm::StringRef name,
93+
mlir::StringAttr linkage = {},
94+
mlir::Attribute value = {}, bool isConst = false);
95+
96+
fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
97+
llvm::StringRef name, bool isConst,
98+
std::function<void(FirOpBuilder &)> bodyBuilder,
99+
mlir::StringAttr linkage = {});
100+
101+
/// Create a global constant (read-only) value.
102+
fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type,
103+
llvm::StringRef name,
104+
mlir::StringAttr linkage = {},
105+
mlir::Attribute value = {}) {
106+
return createGlobal(loc, type, name, linkage, value, /*isConst=*/true);
107+
}
108+
109+
fir::GlobalOp
110+
createGlobalConstant(mlir::Location loc, mlir::Type type,
111+
llvm::StringRef name,
112+
std::function<void(FirOpBuilder &)> bodyBuilder,
113+
mlir::StringAttr linkage = {}) {
114+
return createGlobal(loc, type, name, /*isConst=*/true, bodyBuilder,
115+
linkage);
116+
}
117+
118+
/// Convert a StringRef string into a fir::StringLitOp.
119+
fir::StringLitOp createStringLitOp(mlir::Location loc,
120+
llvm::StringRef string);
121+
122+
//===--------------------------------------------------------------------===//
123+
// Linkage helpers (inline). The default linkage is external.
124+
//===--------------------------------------------------------------------===//
125+
126+
mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); }
127+
128+
mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); }
129+
130+
mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); }
131+
132+
mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); }
56133

57134
/// Cast the input value to IndexType.
58135
mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
59136
return createConvert(loc, getIndexType(), val);
60137
}
61138

139+
/// Get a function by name. If the function exists in the current module, it
140+
/// is returned. Otherwise, a null FuncOp is returned.
141+
mlir::FuncOp getNamedFunction(llvm::StringRef name) {
142+
return getNamedFunction(getModule(), name);
143+
}
144+
145+
static mlir::FuncOp getNamedFunction(mlir::ModuleOp module,
146+
llvm::StringRef name);
147+
148+
fir::GlobalOp getNamedGlobal(llvm::StringRef name) {
149+
return getNamedGlobal(getModule(), name);
150+
}
151+
152+
static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module,
153+
llvm::StringRef name);
154+
155+
/// Lazy creation of fir.convert op.
156+
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
157+
mlir::Value val);
158+
159+
/// Create a new FuncOp. If the function may have already been created, use
160+
/// `addNamedFunction` instead.
161+
mlir::FuncOp createFunction(mlir::Location loc, llvm::StringRef name,
162+
mlir::FunctionType ty) {
163+
return createFunction(loc, getModule(), name, ty);
164+
}
165+
166+
static mlir::FuncOp createFunction(mlir::Location loc, mlir::ModuleOp module,
167+
llvm::StringRef name,
168+
mlir::FunctionType ty);
169+
170+
/// Determine if the named function is already in the module. Return the
171+
/// instance if found, otherwise add a new named function to the module.
172+
mlir::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name,
173+
mlir::FunctionType ty) {
174+
if (auto func = getNamedFunction(name))
175+
return func;
176+
return createFunction(loc, name, ty);
177+
}
178+
179+
static mlir::FuncOp addNamedFunction(mlir::Location loc,
180+
mlir::ModuleOp module,
181+
llvm::StringRef name,
182+
mlir::FunctionType ty) {
183+
if (auto func = getNamedFunction(module, name))
184+
return func;
185+
return createFunction(loc, module, name, ty);
186+
}
187+
188+
/// Create constant i1 with value 1. if \p b is true or 0. otherwise
189+
mlir::Value createBool(mlir::Location loc, bool b) {
190+
return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0);
191+
}
192+
62193
//===--------------------------------------------------------------------===//
63194
// If-Then-Else generation helper
64195
//===--------------------------------------------------------------------===//
@@ -126,8 +257,30 @@ class FirOpBuilder : public mlir::OpBuilder {
126257

127258
/// Generate code testing \p addr is a null address.
128259
mlir::Value genIsNull(mlir::Location loc, mlir::Value addr);
260+
261+
private:
262+
const KindMapping &kindMap;
129263
};
130264

131265
} // namespace fir
132266

267+
namespace fir::factory {
268+
269+
//===--------------------------------------------------------------------===//
270+
// String literal helper helpers
271+
//===--------------------------------------------------------------------===//
272+
273+
/// Unique a compiler generated identifier. A short prefix should be provided
274+
/// to hint at the origin of the identifier.
275+
std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name);
276+
277+
//===----------------------------------------------------------------------===//
278+
// Location helpers
279+
//===----------------------------------------------------------------------===//
280+
281+
/// Generate a constant of the given type with the location line number
282+
mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type);
283+
284+
} // namespace fir::factory
285+
133286
#endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H

flang/lib/Optimizer/Builder/FIRBuilder.cpp

+173
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,145 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Optimizer/Builder/FIRBuilder.h"
10+
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
11+
#include "flang/Optimizer/Support/FatalError.h"
12+
#include "flang/Optimizer/Support/InternalNames.h"
13+
#include "llvm/ADT/StringExtras.h"
14+
#include "llvm/Support/CommandLine.h"
15+
#include "llvm/Support/MD5.h"
16+
17+
static llvm::cl::opt<std::size_t>
18+
nameLengthHashSize("length-to-hash-string-literal",
19+
llvm::cl::desc("string literals that exceed this length"
20+
" will use a hash value as their symbol "
21+
"name"),
22+
llvm::cl::init(32));
23+
24+
mlir::FuncOp fir::FirOpBuilder::createFunction(mlir::Location loc,
25+
mlir::ModuleOp module,
26+
llvm::StringRef name,
27+
mlir::FunctionType ty) {
28+
return fir::createFuncOp(loc, module, name, ty);
29+
}
30+
31+
mlir::FuncOp fir::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp,
32+
llvm::StringRef name) {
33+
return modOp.lookupSymbol<mlir::FuncOp>(name);
34+
}
35+
36+
fir::GlobalOp fir::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp,
37+
llvm::StringRef name) {
38+
return modOp.lookupSymbol<fir::GlobalOp>(name);
39+
}
40+
41+
mlir::Type fir::FirOpBuilder::getRefType(mlir::Type eleTy) {
42+
assert(!eleTy.isa<fir::ReferenceType>() && "cannot be a reference type");
43+
return fir::ReferenceType::get(eleTy);
44+
}
45+
46+
mlir::Type fir::FirOpBuilder::getVarLenSeqTy(mlir::Type eleTy, unsigned rank) {
47+
fir::SequenceType::Shape shape(rank, fir::SequenceType::getUnknownExtent());
48+
return fir::SequenceType::get(shape, eleTy);
49+
}
50+
51+
mlir::Type fir::FirOpBuilder::getRealType(int kind) {
52+
switch (kindMap.getRealTypeID(kind)) {
53+
case llvm::Type::TypeID::HalfTyID:
54+
return mlir::FloatType::getF16(getContext());
55+
case llvm::Type::TypeID::FloatTyID:
56+
return mlir::FloatType::getF32(getContext());
57+
case llvm::Type::TypeID::DoubleTyID:
58+
return mlir::FloatType::getF64(getContext());
59+
case llvm::Type::TypeID::X86_FP80TyID:
60+
return mlir::FloatType::getF80(getContext());
61+
case llvm::Type::TypeID::FP128TyID:
62+
return mlir::FloatType::getF128(getContext());
63+
default:
64+
fir::emitFatalError(UnknownLoc::get(getContext()),
65+
"unsupported type !fir.real<kind>");
66+
}
67+
}
68+
69+
mlir::Value fir::FirOpBuilder::createNullConstant(mlir::Location loc,
70+
mlir::Type ptrType) {
71+
auto ty = ptrType ? ptrType : getRefType(getNoneType());
72+
return create<fir::ZeroOp>(loc, ty);
73+
}
1074

1175
mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc,
1276
mlir::Type ty,
1377
std::int64_t cst) {
1478
return create<mlir::ConstantOp>(loc, ty, getIntegerAttr(ty, cst));
1579
}
1680

81+
mlir::Value
82+
fir::FirOpBuilder::createRealConstant(mlir::Location loc, mlir::Type fltTy,
83+
llvm::APFloat::integerPart val) {
84+
auto apf = [&]() -> llvm::APFloat {
85+
if (auto ty = fltTy.dyn_cast<fir::RealType>())
86+
return llvm::APFloat(kindMap.getFloatSemantics(ty.getFKind()), val);
87+
if (fltTy.isF16())
88+
return llvm::APFloat(llvm::APFloat::IEEEhalf(), val);
89+
if (fltTy.isBF16())
90+
return llvm::APFloat(llvm::APFloat::BFloat(), val);
91+
if (fltTy.isF32())
92+
return llvm::APFloat(llvm::APFloat::IEEEsingle(), val);
93+
if (fltTy.isF64())
94+
return llvm::APFloat(llvm::APFloat::IEEEdouble(), val);
95+
if (fltTy.isF80())
96+
return llvm::APFloat(llvm::APFloat::x87DoubleExtended(), val);
97+
if (fltTy.isF128())
98+
return llvm::APFloat(llvm::APFloat::IEEEquad(), val);
99+
llvm_unreachable("unhandled MLIR floating-point type");
100+
};
101+
return createRealConstant(loc, fltTy, apf());
102+
}
103+
104+
mlir::Value fir::FirOpBuilder::createRealConstant(mlir::Location loc,
105+
mlir::Type fltTy,
106+
const llvm::APFloat &value) {
107+
if (fltTy.isa<mlir::FloatType>()) {
108+
auto attr = getFloatAttr(fltTy, value);
109+
return create<mlir::arith::ConstantOp>(loc, fltTy, attr);
110+
}
111+
llvm_unreachable("should use builtin floating-point type");
112+
}
113+
114+
/// Create a global variable in the (read-only) data section. A global variable
115+
/// must have a unique name to identify and reference it.
116+
fir::GlobalOp
117+
fir::FirOpBuilder::createGlobal(mlir::Location loc, mlir::Type type,
118+
llvm::StringRef name, mlir::StringAttr linkage,
119+
mlir::Attribute value, bool isConst) {
120+
auto module = getModule();
121+
auto insertPt = saveInsertionPoint();
122+
if (auto glob = module.lookupSymbol<fir::GlobalOp>(name))
123+
return glob;
124+
setInsertionPoint(module.getBody(), module.getBody()->end());
125+
auto glob = create<fir::GlobalOp>(loc, name, isConst, type, value, linkage);
126+
restoreInsertionPoint(insertPt);
127+
return glob;
128+
}
129+
130+
fir::GlobalOp fir::FirOpBuilder::createGlobal(
131+
mlir::Location loc, mlir::Type type, llvm::StringRef name, bool isConst,
132+
std::function<void(FirOpBuilder &)> bodyBuilder, mlir::StringAttr linkage) {
133+
auto module = getModule();
134+
auto insertPt = saveInsertionPoint();
135+
if (auto glob = module.lookupSymbol<fir::GlobalOp>(name))
136+
return glob;
137+
setInsertionPoint(module.getBody(), module.getBody()->end());
138+
auto glob = create<fir::GlobalOp>(loc, name, isConst, type, mlir::Attribute{},
139+
linkage);
140+
auto &region = glob.getRegion();
141+
region.push_back(new mlir::Block);
142+
auto &block = glob.getRegion().back();
143+
setInsertionPointToStart(&block);
144+
bodyBuilder(*this);
145+
restoreInsertionPoint(insertPt);
146+
return glob;
147+
}
148+
17149
mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc,
18150
mlir::Type toTy, mlir::Value val) {
19151
if (val.getType() != toTy) {
@@ -23,6 +155,19 @@ mlir::Value fir::FirOpBuilder::createConvert(mlir::Location loc,
23155
return val;
24156
}
25157

158+
fir::StringLitOp fir::FirOpBuilder::createStringLitOp(mlir::Location loc,
159+
llvm::StringRef data) {
160+
auto type = fir::CharacterType::get(getContext(), 1, data.size());
161+
auto strAttr = mlir::StringAttr::get(getContext(), data);
162+
auto valTag = mlir::Identifier::get(fir::StringLitOp::value(), getContext());
163+
mlir::NamedAttribute dataAttr(valTag, strAttr);
164+
auto sizeTag = mlir::Identifier::get(fir::StringLitOp::size(), getContext());
165+
mlir::NamedAttribute sizeAttr(sizeTag, getI64IntegerAttr(data.size()));
166+
llvm::SmallVector<mlir::NamedAttribute> attrs{dataAttr, sizeAttr};
167+
return create<fir::StringLitOp>(loc, llvm::ArrayRef<mlir::Type>{type},
168+
llvm::None, attrs);
169+
}
170+
26171
static mlir::Value genNullPointerComparison(fir::FirOpBuilder &builder,
27172
mlir::Location loc,
28173
mlir::Value addr,
@@ -41,3 +186,31 @@ mlir::Value fir::FirOpBuilder::genIsNotNull(mlir::Location loc,
41186
mlir::Value fir::FirOpBuilder::genIsNull(mlir::Location loc, mlir::Value addr) {
42187
return genNullPointerComparison(*this, loc, addr, arith::CmpIPredicate::eq);
43188
}
189+
190+
std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix,
191+
llvm::StringRef name) {
192+
// For "long" identifiers use a hash value
193+
if (name.size() > nameLengthHashSize) {
194+
llvm::MD5 hash;
195+
hash.update(name);
196+
llvm::MD5::MD5Result result;
197+
hash.final(result);
198+
llvm::SmallString<32> str;
199+
llvm::MD5::stringifyResult(result, str);
200+
std::string hashName = prefix.str();
201+
hashName.append(".").append(str.c_str());
202+
return fir::NameUniquer::doGenerated(hashName);
203+
}
204+
// "Short" identifiers use a reversible hex string
205+
std::string nm = prefix.str();
206+
return fir::NameUniquer::doGenerated(
207+
nm.append(".").append(llvm::toHex(name)));
208+
}
209+
210+
mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder,
211+
mlir::Location loc,
212+
mlir::Type type) {
213+
if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>())
214+
return builder.createIntegerConstant(loc, type, flc.getLine());
215+
return builder.createIntegerConstant(loc, type, 0);
216+
}

0 commit comments

Comments
 (0)