Skip to content

Commit c983aed

Browse files
clementvaljeanPerierschweitzpgi
committed
[fir] Add character utility functions in FIRBuilder
Extract part of D111337 in order to mke it smaller and easier to review. This patch add some utility functions to the FIRBuilder. Add the following utility functions: - getCharacterLengthType - createStringLiteral - locationToFilename - characterWithDynamicLen - sequenceWithNonConstantShape - hasDynamicSize These bring up the BoxValue implementation together with it. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: AlexisPerry Differential Revision: https://reviews.llvm.org/D112074 Co-authored-by: Jean Perier <[email protected]> Co-authored-by: Eric Schweitz <[email protected]>
1 parent 91e19f6 commit c983aed

File tree

10 files changed

+905
-2
lines changed

10 files changed

+905
-2
lines changed

flang/include/flang/Optimizer/Builder/BoxValue.h

Lines changed: 472 additions & 0 deletions
Large diffs are not rendered by default.

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "mlir/IR/BuiltinOps.h"
2424

2525
namespace fir {
26+
class ExtendedValue;
2627

2728
//===----------------------------------------------------------------------===//
2829
// FirOpBuilder
@@ -55,6 +56,9 @@ class FirOpBuilder : public mlir::OpBuilder {
5556
/// Create a sequence of `eleTy` with `rank` dimensions of unknown size.
5657
mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1);
5758

59+
/// Get character length type
60+
mlir::Type getCharacterLengthType() { return getIndexType(); }
61+
5862
/// Get the integer type whose bit width corresponds to the width of pointer
5963
/// types, or is bigger.
6064
mlir::Type getIntPtrType() {
@@ -266,9 +270,14 @@ class FirOpBuilder : public mlir::OpBuilder {
266270

267271
namespace fir::factory {
268272

269-
//===--------------------------------------------------------------------===//
273+
//===----------------------------------------------------------------------===//
270274
// String literal helper helpers
271-
//===--------------------------------------------------------------------===//
275+
//===----------------------------------------------------------------------===//
276+
277+
/// Create a !fir.char<1> string literal global and returns a
278+
/// fir::CharBoxValue with its address and length.
279+
fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location,
280+
llvm::StringRef string);
272281

273282
/// Unique a compiler generated identifier. A short prefix should be provided
274283
/// to hint at the origin of the identifier.
@@ -278,6 +287,9 @@ std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name);
278287
// Location helpers
279288
//===----------------------------------------------------------------------===//
280289

290+
/// Generate a string literal containing the file name and return its address
291+
mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location);
292+
281293
/// Generate a constant of the given type with the location line number
282294
mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type);
283295

flang/include/flang/Optimizer/Dialect/FIRType.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ inline bool isa_char_string(mlir::Type t) {
138138
/// of unknown rank or type.
139139
bool isa_unknown_size_box(mlir::Type t);
140140

141+
/// Returns true iff `t` is a fir.char type and has an unknown length.
142+
inline bool characterWithDynamicLen(mlir::Type t) {
143+
if (auto charTy = t.dyn_cast<fir::CharacterType>())
144+
return charTy.hasDynamicLen();
145+
return false;
146+
}
147+
148+
/// Returns true iff `seqTy` has either an unknown shape or a non-constant shape
149+
/// (where rank > 0).
150+
inline bool sequenceWithNonConstantShape(fir::SequenceType seqTy) {
151+
return seqTy.hasUnknownShape() || !seqTy.hasConstantShape();
152+
}
153+
154+
/// Returns true iff the type `t` does not have a constant size.
155+
bool hasDynamicSize(mlir::Type t);
156+
141157
/// If `t` is a SequenceType return its element type, otherwise return `t`.
142158
inline mlir::Type unwrapSequenceType(mlir::Type t) {
143159
if (auto seqTy = t.dyn_cast<fir::SequenceType>())
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===-- Optimizer/Support/Matcher.h -----------------------------*- C++ -*-===//
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+
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_OPTIMIZER_SUPPORT_MATCHER_H
14+
#define FORTRAN_OPTIMIZER_SUPPORT_MATCHER_H
15+
16+
#include <variant>
17+
18+
// Boilerplate CRTP class for a simplified type-casing syntactic sugar. This
19+
// lets one write pattern matchers using a more compact syntax.
20+
namespace fir::details {
21+
// clang-format off
22+
template<class... Ts> struct matches : Ts... { using Ts::operator()...; };
23+
template<class... Ts> matches(Ts...) -> matches<Ts...>;
24+
template<typename N> struct matcher {
25+
template<typename... Ts> auto match(Ts... ts) {
26+
return std::visit(matches{ts...}, static_cast<N*>(this)->matchee());
27+
}
28+
template<typename... Ts> auto match(Ts... ts) const {
29+
return std::visit(matches{ts...}, static_cast<N const*>(this)->matchee());
30+
}
31+
};
32+
// clang-format on
33+
} // namespace fir::details
34+
35+
#endif // FORTRAN_OPTIMIZER_SUPPORT_MATCHER_H
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
//===-- BoxValue.cpp ------------------------------------------------------===//
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+
// Pretty printers for box values, etc.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "flang/Optimizer/Builder/BoxValue.h"
14+
#include "mlir/IR/BuiltinTypes.h"
15+
#include "llvm/Support/Debug.h"
16+
17+
#define DEBUG_TYPE "flang-box-value"
18+
19+
mlir::Value fir::getBase(const fir::ExtendedValue &exv) {
20+
return exv.match([](const fir::UnboxedValue &x) { return x; },
21+
[](const auto &x) { return x.getAddr(); });
22+
}
23+
24+
mlir::Value fir::getLen(const fir::ExtendedValue &exv) {
25+
return exv.match(
26+
[](const fir::CharBoxValue &x) { return x.getLen(); },
27+
[](const fir::CharArrayBoxValue &x) { return x.getLen(); },
28+
[](const fir::BoxValue &) -> mlir::Value {
29+
llvm::report_fatal_error("Need to read len from BoxValue Exv");
30+
},
31+
[](const fir::MutableBoxValue &) -> mlir::Value {
32+
llvm::report_fatal_error("Need to read len from MutableBoxValue Exv");
33+
},
34+
[](const auto &) { return mlir::Value{}; });
35+
}
36+
37+
fir::ExtendedValue fir::substBase(const fir::ExtendedValue &exv,
38+
mlir::Value base) {
39+
return exv.match(
40+
[=](const fir::UnboxedValue &x) { return fir::ExtendedValue(base); },
41+
[=](const fir::BoxValue &) -> fir::ExtendedValue {
42+
llvm::report_fatal_error("TODO: substbase of BoxValue");
43+
},
44+
[=](const fir::MutableBoxValue &) -> fir::ExtendedValue {
45+
llvm::report_fatal_error("TODO: substbase of MutableBoxValue");
46+
},
47+
[=](const auto &x) { return fir::ExtendedValue(x.clone(base)); });
48+
}
49+
50+
llvm::SmallVector<mlir::Value> fir::getTypeParams(const ExtendedValue &exv) {
51+
using RT = llvm::SmallVector<mlir::Value>;
52+
auto baseTy = fir::getBase(exv).getType();
53+
if (auto t = fir::dyn_cast_ptrEleTy(baseTy))
54+
baseTy = t;
55+
baseTy = fir::unwrapSequenceType(baseTy);
56+
if (!fir::hasDynamicSize(baseTy))
57+
return {}; // type has constant size, no type parameters needed
58+
[[maybe_unused]] auto loc = fir::getBase(exv).getLoc();
59+
return exv.match(
60+
[](const fir::CharBoxValue &x) -> RT { return {x.getLen()}; },
61+
[](const fir::CharArrayBoxValue &x) -> RT { return {x.getLen()}; },
62+
[&](const fir::BoxValue &) -> RT {
63+
LLVM_DEBUG(mlir::emitWarning(
64+
loc, "TODO: box value is missing type parameters"));
65+
return {};
66+
},
67+
[&](const fir::MutableBoxValue &) -> RT {
68+
// In this case, the type params may be bound to the variable in an
69+
// ALLOCATE statement as part of a type-spec.
70+
LLVM_DEBUG(mlir::emitWarning(
71+
loc, "TODO: mutable box value is missing type parameters"));
72+
return {};
73+
},
74+
[](const auto &) -> RT { return {}; });
75+
}
76+
77+
bool fir::isArray(const fir::ExtendedValue &exv) {
78+
return exv.match(
79+
[](const fir::ArrayBoxValue &) { return true; },
80+
[](const fir::CharArrayBoxValue &) { return true; },
81+
[](const fir::BoxValue &box) { return box.hasRank(); },
82+
[](const fir::MutableBoxValue &box) { return box.hasRank(); },
83+
[](auto) { return false; });
84+
}
85+
86+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
87+
const fir::CharBoxValue &box) {
88+
return os << "boxchar { addr: " << box.getAddr() << ", len: " << box.getLen()
89+
<< " }";
90+
}
91+
92+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
93+
const fir::ArrayBoxValue &box) {
94+
os << "boxarray { addr: " << box.getAddr();
95+
if (box.getLBounds().size()) {
96+
os << ", lbounds: [";
97+
llvm::interleaveComma(box.getLBounds(), os);
98+
os << "]";
99+
} else {
100+
os << ", lbounds: all-ones";
101+
}
102+
os << ", shape: [";
103+
llvm::interleaveComma(box.getExtents(), os);
104+
return os << "]}";
105+
}
106+
107+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
108+
const fir::CharArrayBoxValue &box) {
109+
os << "boxchararray { addr: " << box.getAddr() << ", len : " << box.getLen();
110+
if (box.getLBounds().size()) {
111+
os << ", lbounds: [";
112+
llvm::interleaveComma(box.getLBounds(), os);
113+
os << "]";
114+
} else {
115+
os << " lbounds: all-ones";
116+
}
117+
os << ", shape: [";
118+
llvm::interleaveComma(box.getExtents(), os);
119+
return os << "]}";
120+
}
121+
122+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
123+
const fir::ProcBoxValue &box) {
124+
return os << "boxproc: { procedure: " << box.getAddr()
125+
<< ", context: " << box.hostContext << "}";
126+
}
127+
128+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
129+
const fir::BoxValue &box) {
130+
os << "box: { value: " << box.getAddr();
131+
if (box.lbounds.size()) {
132+
os << ", lbounds: [";
133+
llvm::interleaveComma(box.lbounds, os);
134+
os << "]";
135+
}
136+
if (!box.explicitParams.empty()) {
137+
os << ", explicit type params: [";
138+
llvm::interleaveComma(box.explicitParams, os);
139+
os << "]";
140+
}
141+
if (!box.extents.empty()) {
142+
os << ", explicit extents: [";
143+
llvm::interleaveComma(box.extents, os);
144+
os << "]";
145+
}
146+
return os << "}";
147+
}
148+
149+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
150+
const fir::MutableBoxValue &box) {
151+
os << "mutablebox: { addr: " << box.getAddr();
152+
if (!box.lenParams.empty()) {
153+
os << ", non deferred type params: [";
154+
llvm::interleaveComma(box.lenParams, os);
155+
os << "]";
156+
}
157+
const auto &properties = box.mutableProperties;
158+
if (!properties.isEmpty()) {
159+
os << ", mutableProperties: { addr: " << properties.addr;
160+
if (!properties.lbounds.empty()) {
161+
os << ", lbounds: [";
162+
llvm::interleaveComma(properties.lbounds, os);
163+
os << "]";
164+
}
165+
if (!properties.extents.empty()) {
166+
os << ", shape: [";
167+
llvm::interleaveComma(properties.extents, os);
168+
os << "]";
169+
}
170+
if (!properties.deferredParams.empty()) {
171+
os << ", deferred type params: [";
172+
llvm::interleaveComma(properties.deferredParams, os);
173+
os << "]";
174+
}
175+
os << "}";
176+
}
177+
return os << "}";
178+
}
179+
180+
llvm::raw_ostream &fir::operator<<(llvm::raw_ostream &os,
181+
const fir::ExtendedValue &exv) {
182+
exv.match([&](const auto &value) { os << value; });
183+
return os;
184+
}
185+
186+
/// Debug verifier for MutableBox ctor. There is no guarantee that this will
187+
/// always be called, so it should not have any functional side effects,
188+
/// the const is here to enforce that.
189+
bool fir::MutableBoxValue::verify() const {
190+
auto type = fir::dyn_cast_ptrEleTy(getAddr().getType());
191+
if (!type)
192+
return false;
193+
auto box = type.dyn_cast<fir::BoxType>();
194+
if (!box)
195+
return false;
196+
auto eleTy = box.getEleTy();
197+
if (!eleTy.isa<fir::PointerType>() && !eleTy.isa<fir::HeapType>())
198+
return false;
199+
200+
auto nParams = lenParams.size();
201+
if (isCharacter()) {
202+
if (nParams > 1)
203+
return false;
204+
} else if (!isDerived()) {
205+
if (nParams != 0)
206+
return false;
207+
}
208+
return true;
209+
}
210+
211+
/// Debug verifier for BoxValue ctor. There is no guarantee this will
212+
/// always be called.
213+
bool fir::BoxValue::verify() const {
214+
if (!addr.getType().isa<fir::BoxType>())
215+
return false;
216+
if (!lbounds.empty() && lbounds.size() != rank())
217+
return false;
218+
// Explicit extents are here to cover cases where an explicit-shape dummy
219+
// argument comes as a fir.box. This can only happen with derived types and
220+
// unlimited polymorphic.
221+
if (!extents.empty() && !(isDerived() || isUnlimitedPolymorphic()))
222+
return false;
223+
if (!extents.empty() && extents.size() != rank())
224+
return false;
225+
if (isCharacter() && explicitParams.size() > 1)
226+
return false;
227+
return true;
228+
}

flang/lib/Optimizer/Builder/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
22
add_flang_library(FIRBuilder
3+
BoxValue.cpp
34
DoLoopHelper.cpp
45
FIRBuilder.cpp
56

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "flang/Optimizer/Builder/FIRBuilder.h"
10+
#include "flang/Optimizer/Builder/BoxValue.h"
1011
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
1112
#include "flang/Optimizer/Support/FatalError.h"
1213
#include "flang/Optimizer/Support/InternalNames.h"
@@ -207,10 +208,41 @@ std::string fir::factory::uniqueCGIdent(llvm::StringRef prefix,
207208
nm.append(".").append(llvm::toHex(name)));
208209
}
209210

211+
mlir::Value fir::factory::locationToFilename(fir::FirOpBuilder &builder,
212+
mlir::Location loc) {
213+
if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>()) {
214+
// must be encoded as asciiz, C string
215+
auto fn = flc.getFilename().str() + '\0';
216+
return fir::getBase(createStringLiteral(builder, loc, fn));
217+
}
218+
return builder.createNullConstant(loc);
219+
}
220+
210221
mlir::Value fir::factory::locationToLineNo(fir::FirOpBuilder &builder,
211222
mlir::Location loc,
212223
mlir::Type type) {
213224
if (auto flc = loc.dyn_cast<mlir::FileLineColLoc>())
214225
return builder.createIntegerConstant(loc, type, flc.getLine());
215226
return builder.createIntegerConstant(loc, type, 0);
216227
}
228+
229+
fir::ExtendedValue fir::factory::createStringLiteral(fir::FirOpBuilder &builder,
230+
mlir::Location loc,
231+
llvm::StringRef str) {
232+
std::string globalName = fir::factory::uniqueCGIdent("cl", str);
233+
auto type = fir::CharacterType::get(builder.getContext(), 1, str.size());
234+
auto global = builder.getNamedGlobal(globalName);
235+
if (!global)
236+
global = builder.createGlobalConstant(
237+
loc, type, globalName,
238+
[&](fir::FirOpBuilder &builder) {
239+
auto stringLitOp = builder.createStringLitOp(loc, str);
240+
builder.create<fir::HasValueOp>(loc, stringLitOp);
241+
},
242+
builder.createLinkOnceLinkage());
243+
auto addr = builder.create<fir::AddrOfOp>(loc, global.resultType(),
244+
global.getSymbol());
245+
auto len = builder.createIntegerConstant(
246+
loc, builder.getCharacterLengthType(), str.size());
247+
return fir::CharBoxValue{addr, len};
248+
}

0 commit comments

Comments
 (0)