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