-
Notifications
You must be signed in to change notification settings - Fork 10.8k
/
Character.h
233 lines (191 loc) · 10.6 KB
/
Character.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
//===-- Character.h -- lowering of characters -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H
#define FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H
#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Builder/LowLevelIntrinsics.h"
namespace fir {
class FirOpBuilder;
}
namespace fir::factory {
/// Helper to facilitate lowering of CHARACTER in FIR.
class CharacterExprHelper {
public:
/// Constructor.
explicit CharacterExprHelper(FirOpBuilder &builder, mlir::Location loc)
: builder{builder}, loc{loc} {}
CharacterExprHelper(const CharacterExprHelper &) = delete;
/// Copy the \p count first characters of \p src into \p dest.
/// \p count can have any integer type.
void createCopy(const fir::CharBoxValue &dest, const fir::CharBoxValue &src,
mlir::Value count);
/// Set characters of \p str at position [\p lower, \p upper) to blanks.
/// \p lower and \upper bounds are zero based.
/// If \p upper <= \p lower, no padding is done.
/// \p upper and \p lower can have any integer type.
void createPadding(const fir::CharBoxValue &str, mlir::Value lower,
mlir::Value upper);
/// Create str(lb:ub), lower bounds must always be specified, upper
/// bound is optional.
fir::CharBoxValue createSubstring(const fir::CharBoxValue &str,
llvm::ArrayRef<mlir::Value> bounds);
/// Compute substring base address given the raw address (not fir.boxchar) of
/// a scalar string, a substring / lower bound, and the substring type.
mlir::Value genSubstringBase(mlir::Value stringRawAddr,
mlir::Value lowerBound,
mlir::Type substringAddrType,
mlir::Value one = {});
/// Return blank character of given \p type !fir.char<kind>
mlir::Value createBlankConstant(fir::CharacterType type);
/// Lower \p lhs = \p rhs where \p lhs and \p rhs are scalar characters.
/// It handles cases where \p lhs and \p rhs may overlap.
void createAssign(const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs);
/// Create lhs // rhs in temp obtained with fir.alloca
fir::CharBoxValue createConcatenate(const fir::CharBoxValue &lhs,
const fir::CharBoxValue &rhs);
/// LEN_TRIM intrinsic.
mlir::Value createLenTrim(const fir::CharBoxValue &str);
/// Embox \p addr and \p len and return fir.boxchar.
/// Take care of type conversions before emboxing.
/// \p len is converted to the integer type for character lengths if needed.
mlir::Value createEmboxChar(mlir::Value addr, mlir::Value len);
/// Create a fir.boxchar for \p str. If \p str is not in memory, a temp is
/// allocated to create the fir.boxchar.
mlir::Value createEmbox(const fir::CharBoxValue &str);
/// Embox a string array. Note that the size/shape of the array is not
/// retrievable from the resulting mlir::Value.
mlir::Value createEmbox(const fir::CharArrayBoxValue &str);
/// Convert character array to a scalar by reducing the extents into the
/// length. Will fail if call on non reference like base.
fir::CharBoxValue toScalarCharacter(const fir::CharArrayBoxValue &);
/// Unbox \p boxchar into (fir.ref<fir.char<kind>>, character length type).
std::pair<mlir::Value, mlir::Value> createUnboxChar(mlir::Value boxChar);
/// Allocate a temp of fir::CharacterType type and length len.
/// Returns related fir.ref<fir.array<? x fir.char<kind>>>.
fir::CharBoxValue createCharacterTemp(mlir::Type type, mlir::Value len);
/// Allocate a temp of compile time constant length.
/// Returns related fir.ref<fir.array<len x fir.char<kind>>>.
fir::CharBoxValue createCharacterTemp(mlir::Type type, int len);
/// Create a temporary with the same kind, length, and value as source.
fir::CharBoxValue createTempFrom(const fir::ExtendedValue &source);
/// Return true if \p type is a character literal type (is
/// `fir.array<len x fir.char<kind>>`).;
static bool isCharacterLiteral(mlir::Type type);
/// Return true if \p type is one of the following type
/// - fir.boxchar<kind>
/// - fir.ref<fir.char<kind,len>>
/// - fir.char<kind,len>
static bool isCharacterScalar(mlir::Type type);
/// Does this extended value base type is fir.char<kind,len>
/// where len is not the unknown extent ?
static bool hasConstantLengthInType(const fir::ExtendedValue &);
/// Extract the kind of a character type
static fir::KindTy getCharacterKind(mlir::Type type);
/// Extract the kind of a character or array of character type.
static fir::KindTy getCharacterOrSequenceKind(mlir::Type type);
// TODO: Do we really need all these flavors of unwrapping to get the fir.char
// type? Or can we merge these? It would be better to merge them and eliminate
// the confusion.
/// Determine the inner character type. Unwraps references, boxes, and
/// sequences to find the !fir.char element type.
static fir::CharacterType getCharType(mlir::Type type);
/// Get fir.char<kind> type with the same kind as inside str.
static fir::CharacterType getCharacterType(mlir::Type type);
static fir::CharacterType getCharacterType(const fir::CharBoxValue &box);
static fir::CharacterType getCharacterType(mlir::Value str);
/// Create an extended value from a value of type:
/// - fir.boxchar<kind>
/// - fir.ref<fir.char<kind,len>>
/// - fir.char<kind,len>
/// or the array versions:
/// - fir.ref<fir.array<n x...x fir.char<kind,len>>>
/// - fir.array<n x...x fir.char<kind,len>>
///
/// Does the heavy lifting of converting the value \p character (along with an
/// optional \p len value) to an extended value. If \p len is null, a length
/// value is extracted from \p character (or its type). This will produce an
/// error if it's not possible. The returned value is a CharBoxValue if \p
/// character is a scalar, otherwise it is a CharArrayBoxValue.
fir::ExtendedValue toExtendedValue(mlir::Value character,
mlir::Value len = {});
/// Is `type` a sequence (array) of CHARACTER type? Return true for any of the
/// following cases:
/// - !fir.array<dim x ... x !fir.char<kind, len>>
/// - !fir.ref<T> where T is either of the first case
/// - !fir.box<T> where T is either of the first case
///
/// In certain contexts, Fortran allows an array of CHARACTERs to be treated
/// as if it were one longer CHARACTER scalar, each element append to the
/// previous.
static bool isArray(mlir::Type type);
/// Temporary helper to help migrating towards properties of
/// ExtendedValue containing characters.
/// Mainly, this ensure that characters are always CharArrayBoxValue,
/// CharBoxValue, or BoxValue and that the base address is not a boxchar.
/// Return the argument if this is not a character.
/// TODO: Create and propagate ExtendedValue according to properties listed
/// above instead of fixing it when needed.
fir::ExtendedValue cleanUpCharacterExtendedValue(const fir::ExtendedValue &);
/// Create fir.char<kind> singleton from \p code integer value.
mlir::Value createSingletonFromCode(mlir::Value code, int kind);
/// Returns integer value held in a character singleton.
mlir::Value extractCodeFromSingleton(mlir::Value singleton);
/// Create a value for the length of a character based on its memory reference
/// that may be a boxchar, box or !fir.[ptr|ref|heap]<fir.char<kind, len>>. If
/// the memref is a simple address and the length is not constant in type, the
/// returned length will be empty.
mlir::Value getLength(mlir::Value memref);
/// Compute length given a fir.box describing a character entity.
/// It adjusts the length from the number of bytes per the descriptor
/// to the number of characters per the Fortran KIND.
mlir::Value readLengthFromBox(mlir::Value box);
/// Same as readLengthFromBox but the CharacterType is provided.
mlir::Value readLengthFromBox(mlir::Value box, fir::CharacterType charTy);
private:
/// FIXME: the implementation also needs a clean-up now that
/// CharBoxValue are better propagated.
fir::CharBoxValue materializeValue(mlir::Value str);
mlir::Value getCharBoxBuffer(const fir::CharBoxValue &box);
mlir::Value createElementAddr(mlir::Value buffer, mlir::Value index);
mlir::Value createLoadCharAt(mlir::Value buff, mlir::Value index);
void createStoreCharAt(mlir::Value str, mlir::Value index, mlir::Value c);
void createLengthOneAssign(const fir::CharBoxValue &lhs,
const fir::CharBoxValue &rhs);
void createAssign(const fir::CharBoxValue &lhs, const fir::CharBoxValue &rhs);
mlir::Value createBlankConstantCode(fir::CharacterType type);
private:
FirOpBuilder &builder;
mlir::Location loc;
};
//===----------------------------------------------------------------------===//
// Tools to work with Character dummy procedures
//===----------------------------------------------------------------------===//
/// Create a tuple<function type, length type> type to pass character functions
/// as arguments along their length. The function type set in the tuple is the
/// one provided by \p funcPointerType.
mlir::Type getCharacterProcedureTupleType(mlir::Type funcPointerType);
/// Create a tuple<addr, len> given \p addr and \p len as well as the tuple
/// type \p argTy. \p addr must be any function address, and \p len may be any
/// integer or nullptr. Converts will be inserted if needed if \addr and \p len
/// types are not the same as the one inside the tuple type \p tupleType.
mlir::Value createCharacterProcedureTuple(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::Type tupleType,
mlir::Value addr, mlir::Value len);
/// Given a tuple containing a character function address and its result length,
/// extract the tuple into a pair of value <function address, result length>.
std::pair<mlir::Value, mlir::Value>
extractCharacterProcedureTuple(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value tuple);
} // namespace fir::factory
#endif // FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H