blob: 6f75448a5dbbfe173243ab4d8f44d04604f14445 [file] [log] [blame]
//===-- Lower/CharacterExpr.h -- lowering of characters ---------*- C++ -*-===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "flang/Lower/FIRBuilder.h"
#include "flang/Lower/Support/BoxValue.h"
namespace Fortran::lower {
/// Helper to facilitate lowering of CHARACTER in FIR.
class CharacterExprHelper {
/// Constructor.
explicit CharacterExprHelper(FirOpBuilder &builder, mlir::Location loc)
: builder{builder}, loc{loc} {}
CharacterExprHelper(const CharacterExprHelper &) = delete;
/// Unless otherwise stated, all mlir::Value inputs of these pseudo-fir ops
/// must be of type:
/// - fir.boxchar<kind> (dynamic length character),
/// - fir.ref<fir.array<len x fir.char<kind>>> (character with compile time
/// constant length),
/// - fir.array<len x fir.char<kind>> (compile time constant character)
/// Copy the \p count first characters of \p src into \p dest.
/// \p count can have any integer type.
void createCopy(mlir::Value dest, mlir::Value 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(mlir::Value str, mlir::Value lower, mlir::Value upper);
/// Create str(lb:ub), lower bounds must always be specified, upper
/// bound is optional.
mlir::Value createSubstring(mlir::Value 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(mlir::Value lhs, mlir::Value rhs);
/// Lower an assignment where the buffer and LEN parameter are known and do
/// not need to be unboxed.
void createAssign(mlir::Value lptr, mlir::Value llen, mlir::Value rptr,
mlir::Value rlen);
/// Create lhs // rhs in temp obtained with fir.alloca
mlir::Value createConcatenate(mlir::Value lhs, mlir::Value rhs);
/// LEN_TRIM intrinsic.
mlir::Value createLenTrim(mlir::Value 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);
/// Unbox \p boxchar into (fir.ref<fir.char<kind>>, getLengthType()).
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.char<kind>>.
mlir::Value 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>>>.
mlir::Value createCharacterTemp(mlir::Type type, int len) {
return createTemp(type, len);
/// Return buffer/length pair of character str, if str is a constant,
/// it is allocated into a temp, otherwise, its memory reference is
/// returned as the buffer.
/// The buffer type of str is of type:
/// - fir.ref<fir.array<len x fir.char<kind>>> if str has compile time
/// constant length.
/// - fir.ref<fir.char<kind>> if str has dynamic length.
std::pair<mlir::Value, mlir::Value> materializeCharacter(mlir::Value str);
/// 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.array<len x fir.char<kind>>>
/// - fir.array<len x fir.char<kind>>
static bool isCharacter(mlir::Type type);
/// Extract the kind of a character type
static int getCharacterKind(mlir::Type type);
/// Return the integer type that must be used to manipulate
/// Character lengths. TODO: move this to FirOpBuilder?
mlir::Type getLengthType() { return builder.getIndexType(); }
/// Create an extended value from:
/// - fir.boxchar<kind>
/// - fir.ref<fir.array<len x fir.char<kind>>>
/// - fir.array<len x fir.char<kind>>
/// - fir.char<kind>
/// - fir.ref<char<kind>>
/// If the no length is passed, it is attempted to be extracted from \p
/// character (or its type). This will crash if this is 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 = {});
fir::CharBoxValue materializeValue(const fir::CharBoxValue &str);
fir::CharBoxValue toDataLengthPair(mlir::Value character);
mlir::Type getReferenceType(const fir::CharBoxValue &c) const;
mlir::Value createEmbox(const fir::CharBoxValue &str);
mlir::Value createLoadCharAt(const fir::CharBoxValue &str, mlir::Value index);
void createStoreCharAt(const fir::CharBoxValue &str, mlir::Value index,
mlir::Value c);
void createCopy(const fir::CharBoxValue &dest, const fir::CharBoxValue &src,
mlir::Value count);
void createPadding(const fir::CharBoxValue &str, mlir::Value lower,
mlir::Value upper);
fir::CharBoxValue createTemp(mlir::Type type, mlir::Value len);
void createLengthOneAssign(const fir::CharBoxValue &lhs,
const fir::CharBoxValue &rhs);
void createAssign(const fir::CharBoxValue &lhs, const fir::CharBoxValue &rhs);
fir::CharBoxValue createConcatenate(const fir::CharBoxValue &lhs,
const fir::CharBoxValue &rhs);
fir::CharBoxValue createSubstring(const fir::CharBoxValue &str,
llvm::ArrayRef<mlir::Value> bounds);
mlir::Value createLenTrim(const fir::CharBoxValue &str);
mlir::Value createTemp(mlir::Type type, int len);
mlir::Value createBlankConstantCode(fir::CharacterType type);
FirOpBuilder &builder;
mlir::Location loc;
} // namespace Fortran::lower