| //===-- 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/FIRBuilder.h" |
| |
| 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); |
| |
| /// 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); |
| |
| /// Determine the base character type |
| 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); |
| |
| 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); |
| |
| FirOpBuilder &builder; |
| mlir::Location loc; |
| }; |
| |
| // FIXME: Move these to Optimizer |
| mlir::FuncOp getLlvmMemcpy(FirOpBuilder &builder); |
| mlir::FuncOp getLlvmMemmove(FirOpBuilder &builder); |
| mlir::FuncOp getLlvmMemset(FirOpBuilder &builder); |
| mlir::FuncOp getRealloc(FirOpBuilder &builder); |
| |
| } // namespace fir::factory |
| |
| #endif // FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H |