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