Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[flang] Add CHARACTER type lowering helpers and runtime.
In order for these files to build properly, this patch rolls up a number of changes that have been made to various files that have been upstreamed. Implementations for the interfaces included in Bridge.h and IntrinsicCall.h will be included in a future diff. Differential revision: https://reviews.llvm.org/D82608
- Loading branch information
1 parent
ae74252
commit c3477c5
Showing
16 changed files
with
1,123 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//===-- Lower/Bridge.h -- main interface to lowering ------------*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
/// | ||
/// \file | ||
/// Implements lowering. Convert Fortran source to | ||
/// [MLIR](https://github.com/tensorflow/mlir). | ||
/// | ||
/// [Coding style](https://llvm.org/docs/CodingStandards.html) | ||
/// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef FORTRAN_LOWER_BRIDGE_H | ||
#define FORTRAN_LOWER_BRIDGE_H | ||
|
||
#include "flang/Common/Fortran.h" | ||
#include "flang/Lower/AbstractConverter.h" | ||
#include "flang/Optimizer/Support/KindMapping.h" | ||
#include "mlir/IR/Module.h" | ||
|
||
namespace fir { | ||
struct NameUniquer; | ||
} | ||
|
||
namespace Fortran { | ||
namespace common { | ||
class IntrinsicTypeDefaultKinds; | ||
} // namespace common | ||
namespace evaluate { | ||
class IntrinsicProcTable; | ||
} // namespace evaluate | ||
namespace parser { | ||
class CookedSource; | ||
struct Program; | ||
} // namespace parser | ||
namespace semantics { | ||
class SemanticsContext; | ||
} // namespace semantics | ||
|
||
namespace lower { | ||
|
||
//===----------------------------------------------------------------------===// | ||
// Lowering bridge | ||
//===----------------------------------------------------------------------===// | ||
|
||
/// The lowering bridge converts the front-end parse trees and semantics | ||
/// checking residual to MLIR (FIR dialect) code. | ||
class LoweringBridge { | ||
public: | ||
/// Create a lowering bridge instance. | ||
static LoweringBridge | ||
create(const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds, | ||
const Fortran::evaluate::IntrinsicProcTable &intrinsics, | ||
const Fortran::parser::CookedSource &cooked) { | ||
return LoweringBridge{defaultKinds, intrinsics, cooked}; | ||
} | ||
|
||
//===--------------------------------------------------------------------===// | ||
// Getters | ||
//===--------------------------------------------------------------------===// | ||
|
||
mlir::MLIRContext &getMLIRContext() { return *context.get(); } | ||
mlir::ModuleOp &getModule() { return *module.get(); } | ||
const Fortran::common::IntrinsicTypeDefaultKinds &getDefaultKinds() const { | ||
return defaultKinds; | ||
} | ||
const Fortran::evaluate::IntrinsicProcTable &getIntrinsicTable() const { | ||
return intrinsics; | ||
} | ||
const Fortran::parser::CookedSource *getCookedSource() const { | ||
return cooked; | ||
} | ||
|
||
/// Get the kind map. | ||
const fir::KindMapping &getKindMap() const { return kindMap; } | ||
|
||
/// Create a folding context. Careful: this is very expensive. | ||
Fortran::evaluate::FoldingContext createFoldingContext() const; | ||
|
||
bool validModule() { return getModule(); } | ||
|
||
//===--------------------------------------------------------------------===// | ||
// Perform the creation of an mlir::ModuleOp | ||
//===--------------------------------------------------------------------===// | ||
|
||
/// Read in an MLIR input file rather than lowering Fortran sources. | ||
/// This is intended to be used for testing. | ||
void parseSourceFile(llvm::SourceMgr &); | ||
|
||
/// Cross the bridge from the Fortran parse-tree, etc. to MLIR dialects | ||
void lower(const Fortran::parser::Program &program, fir::NameUniquer &uniquer, | ||
const Fortran::semantics::SemanticsContext &semanticsContext); | ||
|
||
private: | ||
explicit LoweringBridge( | ||
const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds, | ||
const Fortran::evaluate::IntrinsicProcTable &intrinsics, | ||
const Fortran::parser::CookedSource &cooked); | ||
LoweringBridge() = delete; | ||
LoweringBridge(const LoweringBridge &) = delete; | ||
|
||
const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds; | ||
const Fortran::evaluate::IntrinsicProcTable &intrinsics; | ||
const Fortran::parser::CookedSource *cooked; | ||
std::unique_ptr<mlir::MLIRContext> context; | ||
std::unique_ptr<mlir::ModuleOp> module; | ||
fir::KindMapping kindMap; | ||
}; | ||
|
||
} // namespace lower | ||
} // namespace Fortran | ||
|
||
#endif // FORTRAN_LOWER_BRIDGE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
//===-- Lower/CharacterExpr.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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef FORTRAN_LOWER_CHARACTEREXPR_H | ||
#define FORTRAN_LOWER_CHARACTEREXPR_H | ||
|
||
#include "flang/Lower/FIRBuilder.h" | ||
#include "flang/Lower/Support/BoxValue.h" | ||
|
||
namespace Fortran::lower { | ||
|
||
/// 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; | ||
|
||
/// 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(); } | ||
|
||
private: | ||
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); | ||
|
||
private: | ||
FirOpBuilder &builder; | ||
mlir::Location loc; | ||
}; | ||
|
||
} // namespace Fortran::lower | ||
|
||
#endif // FORTRAN_LOWER_CHARACTEREXPR_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
//===-- Lower/CharacterRuntime.h -- lower CHARACTER operations --*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef FORTRAN_LOWER_CHARACTERRUNTIME_H | ||
#define FORTRAN_LOWER_CHARACTERRUNTIME_H | ||
|
||
#include "mlir/Dialect/StandardOps/IR/Ops.h" | ||
|
||
namespace Fortran { | ||
namespace lower { | ||
class AbstractConverter; | ||
|
||
/// Generate call to a character comparison for two ssa-values of type | ||
/// `boxchar`. | ||
mlir::Value genBoxCharCompare(AbstractConverter &converter, mlir::Location loc, | ||
mlir::CmpIPredicate cmp, mlir::Value lhs, | ||
mlir::Value rhs); | ||
|
||
/// Generate call to a character comparison op for two unboxed variables. There | ||
/// are 4 arguments, 2 for the lhs and 2 for the rhs. Each CHARACTER must pass a | ||
/// reference to its buffer (`ref<char<K>>`) and its LEN type parameter (some | ||
/// integral type). | ||
mlir::Value genRawCharCompare(AbstractConverter &converter, mlir::Location loc, | ||
mlir::CmpIPredicate cmp, mlir::Value lhsBuff, | ||
mlir::Value lhsLen, mlir::Value rhsBuff, | ||
mlir::Value rhsLen); | ||
|
||
} // namespace lower | ||
} // namespace Fortran | ||
|
||
#endif // FORTRAN_LOWER_CHARACTERRUNTIME_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
//===-- Lower/IntrinsicCall.h -- lowering of intrinsics ---------*- 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 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef FORTRAN_LOWER_INTRINSICCALL_H | ||
#define FORTRAN_LOWER_INTRINSICCALL_H | ||
|
||
#include "flang/Lower/FIRBuilder.h" | ||
|
||
namespace fir { | ||
class ExtendedValue; | ||
} | ||
|
||
namespace Fortran::lower { | ||
|
||
// TODO: Expose interface to get specific intrinsic function address. | ||
// TODO: Handle intrinsic subroutine. | ||
// TODO: Intrinsics that do not require their arguments to be defined | ||
// (e.g shape inquiries) might not fit in the current interface that | ||
// requires mlir::Value to be provided. | ||
// TODO: Error handling interface ? | ||
// TODO: Implementation is incomplete. Many intrinsics to tbd. | ||
|
||
/// Helper for building calls to intrinsic functions in the runtime support | ||
/// libraries. | ||
class IntrinsicCallOpsHelper { | ||
public: | ||
explicit IntrinsicCallOpsHelper(FirOpBuilder &builder, mlir::Location loc) | ||
: builder(builder), loc(loc) {} | ||
IntrinsicCallOpsHelper(const IntrinsicCallOpsHelper &) = delete; | ||
|
||
/// Generate the FIR+MLIR operations for the generic intrinsic \p name | ||
/// with arguments \p args and expected result type \p resultType. | ||
/// Returned mlir::Value is the returned Fortran intrinsic value. | ||
fir::ExtendedValue genIntrinsicCall(llvm::StringRef name, | ||
mlir::Type resultType, | ||
llvm::ArrayRef<fir::ExtendedValue> args); | ||
|
||
//===--------------------------------------------------------------------===// | ||
// Direct access to intrinsics that may be used by lowering outside | ||
// of intrinsic call lowering. | ||
//===--------------------------------------------------------------------===// | ||
|
||
/// Generate maximum. There must be at least one argument and all arguments | ||
/// must have the same type. | ||
mlir::Value genMax(llvm::ArrayRef<mlir::Value> args); | ||
|
||
/// Generate minimum. Same constraints as genMax. | ||
mlir::Value genMin(llvm::ArrayRef<mlir::Value> args); | ||
|
||
/// Generate power function x**y with given the expected | ||
/// result type. | ||
mlir::Value genPow(mlir::Type resultType, mlir::Value x, mlir::Value y); | ||
|
||
private: | ||
FirOpBuilder &builder; | ||
mlir::Location loc; | ||
}; | ||
|
||
} // namespace Fortran::lower | ||
|
||
#endif // FORTRAN_LOWER_INTRINSICCALL_H |
Oops, something went wrong.