From: Eric Schweitz Date: Fri, 5 Jun 2020 18:23:22 +0000 (-0700) Subject: [flang] Add the complex expression helper class. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8bba0bca721d66a63709d427ff1e3b48cf7c2cad;p=platform%2Fupstream%2Fllvm.git [flang] Add the complex expression helper class. The complex expression helper class can be used to generate small, short-lived instances of a "helper" that can be used to aid the construction of complex expressions in FIR. The helper class bundles together these functionally related operations. Included in this diff is the header for the FIR builder. The implementation has other dependences and will follow. Differential Revision: https://reviews.llvm.org/D81287 --- diff --git a/flang/include/flang/Lower/ComplexExpr.h b/flang/include/flang/Lower/ComplexExpr.h new file mode 100644 index 0000000..d3600a0 --- /dev/null +++ b/flang/include/flang/Lower/ComplexExpr.h @@ -0,0 +1,83 @@ +//===-- Lower/ComplexExpr.h -- lowering of complex values -------*- 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_COMPLEXEXPR_H +#define FORTRAN_LOWER_COMPLEXEXPR_H + +#include "flang/Lower/FIRBuilder.h" + +namespace Fortran::lower { + +/// Helper to facilitate lowering of COMPLEX manipulations in FIR. +class ComplexExprHelper { +public: + explicit ComplexExprHelper(FirOpBuilder &builder, mlir::Location loc) + : builder(builder), loc(loc) {} + ComplexExprHelper(const ComplexExprHelper &) = delete; + + // The values of part enum members are meaningful for + // InsertValueOp and ExtractValueOp so they are explicit. + enum class Part { Real = 0, Imag = 1 }; + + /// Type helper. Determine the type. Do not create MLIR operations. + mlir::Type getComplexPartType(mlir::Value cplx); + mlir::Type getComplexPartType(mlir::Type complexType); + + /// Complex operation creation helper. They create MLIR operations. + mlir::Value createComplex(fir::KindTy kind, mlir::Value real, + mlir::Value imag); + + /// Create a complex value. + mlir::Value createComplex(mlir::Type complexType, mlir::Value real, + mlir::Value imag); + + mlir::Value extractComplexPart(mlir::Value cplx, bool isImagPart) { + return isImagPart ? extract(cplx) : extract(cplx); + } + + /// Returns (Real, Imag) pair of \p cplx + std::pair extractParts(mlir::Value cplx) { + return {extract(cplx), extract(cplx)}; + } + + mlir::Value insertComplexPart(mlir::Value cplx, mlir::Value part, + bool isImagPart) { + return isImagPart ? insert(cplx, part) + : insert(cplx, part); + } + + mlir::Value createComplexCompare(mlir::Value cplx1, mlir::Value cplx2, + bool eq); + +protected: + template + mlir::Value extract(mlir::Value cplx) { + return builder.create(loc, getComplexPartType(cplx), + cplx, createPartId()); + } + + template + mlir::Value insert(mlir::Value cplx, mlir::Value part) { + return builder.create(loc, cplx.getType(), cplx, part, + createPartId()); + } + + template + mlir::Value createPartId() { + return builder.createIntegerConstant(loc, builder.getIndexType(), + static_cast(partId)); + } + +private: + FirOpBuilder &builder; + mlir::Location loc; +}; + +} // namespace Fortran::lower + +#endif // FORTRAN_LOWER_COMPLEXEXPR_H diff --git a/flang/include/flang/Lower/FIRBuilder.h b/flang/include/flang/Lower/FIRBuilder.h new file mode 100644 index 0000000..f1fb150 --- /dev/null +++ b/flang/include/flang/Lower/FIRBuilder.h @@ -0,0 +1,194 @@ +//===-- Lower/FirBuilder.h -- FIR operation builder -------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Builder routines for constructing the FIR dialect of MLIR. As FIR is a +// dialect of MLIR, it makes extensive use of MLIR interfaces and MLIR's coding +// style (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this +// module. +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_LOWER_FIRBUILDER_H +#define FORTRAN_LOWER_FIRBUILDER_H + +#include "flang/Common/reference.h" +#include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "flang/Optimizer/Support/KindMapping.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/Function.h" +#include "mlir/IR/Module.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" + +namespace Fortran::lower { + +class AbstractConverter; + +//===----------------------------------------------------------------------===// +// FirOpBuilder +//===----------------------------------------------------------------------===// + +/// Extends the MLIR OpBuilder to provide methods for building common FIR +/// patterns. +class FirOpBuilder : public mlir::OpBuilder { +public: + explicit FirOpBuilder(mlir::Operation *op, const fir::KindMapping &kindMap) + : OpBuilder{op}, kindMap{kindMap} {} + + /// Get the current Region of the insertion point. + mlir::Region &getRegion() { return *getBlock()->getParent(); } + + /// Get the current Module + mlir::ModuleOp getModule() { + return getRegion().getParentOfType(); + } + + /// Get the current Function + mlir::FuncOp getFunction() { + return getRegion().getParentOfType(); + } + + /// Get a reference to the kind map. + const fir::KindMapping &getKindMap() { return kindMap; } + + /// The LHS and RHS are not always in agreement in terms of + /// type. In some cases, the disagreement is between COMPLEX and other scalar + /// types. In that case, the conversion must insert/extract out of a COMPLEX + /// value to have the proper semantics and be strongly typed. + mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy, + mlir::Value val); + + /// Get the entry block of the current Function + mlir::Block *getEntryBlock() { return &getFunction().front(); } + + /// Safely create a reference type to the type `eleTy`. + mlir::Type getRefType(mlir::Type eleTy); + + /// Create an integer constant of type \p type and value \p i. + mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, + std::int64_t i); + + mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, + const llvm::APFloat &val); + /// Create a real constant of type \p realType with a value zero. + mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType); + + /// Create a slot for a local on the stack. Besides the variable's type and + /// shape, it may be given name or target attributes. + mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, + llvm::StringRef nm, + llvm::ArrayRef shape, + bool asTarget = false); + + /// Create a temporary. A temp is allocated using `fir.alloca` and can be read + /// and written using `fir.load` and `fir.store`, resp. The temporary can be + /// given a name via a front-end `Symbol` or a `StringRef`. + mlir::Value createTemporary(mlir::Location loc, mlir::Type type, + llvm::StringRef name = {}, + llvm::ArrayRef shape = {}); + + /// Create an unnamed and untracked temporary on the stack. + mlir::Value createTemporary(mlir::Location loc, mlir::Type type, + llvm::ArrayRef shape) { + return createTemporary(loc, type, llvm::StringRef{}, shape); + } + + /// Create a global value. + fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, + llvm::StringRef name, + mlir::StringAttr linkage = {}, + mlir::Attribute value = {}, bool isConst = false); + + fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, + llvm::StringRef name, bool isConst, + std::function bodyBuilder, + mlir::StringAttr linkage = {}); + + /// Create a global constant (read-only) value. + fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type, + llvm::StringRef name, + mlir::StringAttr linkage = {}, + mlir::Attribute value = {}) { + return createGlobal(loc, type, name, linkage, value, /*isConst=*/true); + } + + fir::GlobalOp + createGlobalConstant(mlir::Location loc, mlir::Type type, + llvm::StringRef name, + std::function bodyBuilder, + mlir::StringAttr linkage = {}) { + return createGlobal(loc, type, name, /*isConst=*/true, bodyBuilder, + linkage); + } + + /// Convert a StringRef string into a fir::StringLitOp. + fir::StringLitOp createStringLit(mlir::Location loc, mlir::Type eleTy, + llvm::StringRef string); + + /// Get a function by name. If the function exists in the current module, it + /// is returned. Otherwise, a null FuncOp is returned. + mlir::FuncOp getNamedFunction(llvm::StringRef name) { + return getNamedFunction(getModule(), name); + } + + static mlir::FuncOp getNamedFunction(mlir::ModuleOp module, + llvm::StringRef name); + + fir::GlobalOp getNamedGlobal(llvm::StringRef name) { + return getNamedGlobal(getModule(), name); + } + + static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module, + llvm::StringRef name); + + /// Lazy creation of fir.convert op. + mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, + mlir::Value val); + + /// Create a new FuncOp. If the function may have already been created, use + /// `addNamedFunction` instead. + mlir::FuncOp createFunction(mlir::Location loc, llvm::StringRef name, + mlir::FunctionType ty) { + return createFunction(loc, getModule(), name, ty); + } + + static mlir::FuncOp createFunction(mlir::Location loc, mlir::ModuleOp module, + llvm::StringRef name, + mlir::FunctionType ty); + + /// Determine if the named function is already in the module. Return the + /// instance if found, otherwise add a new named function to the module. + mlir::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name, + mlir::FunctionType ty) { + if (auto func = getNamedFunction(name)) + return func; + return createFunction(loc, name, ty); + } + + static mlir::FuncOp addNamedFunction(mlir::Location loc, + mlir::ModuleOp module, + llvm::StringRef name, + mlir::FunctionType ty) { + if (auto func = getNamedFunction(module, name)) + return func; + return createFunction(loc, module, name, ty); + } + + /// Cast the input value to IndexType. + mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) { + return createConvert(loc, getIndexType(), val); + } + +private: + const fir::KindMapping &kindMap; +}; + +} // namespace Fortran::lower + +#endif // FORTRAN_LOWER_FIRBUILDER_H diff --git a/flang/lib/Lower/CMakeLists.txt b/flang/lib/Lower/CMakeLists.txt index 4473a13e..321fb65 100644 --- a/flang/lib/Lower/CMakeLists.txt +++ b/flang/lib/Lower/CMakeLists.txt @@ -1,6 +1,8 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error -Wno-unused-parameter") add_flang_library(FortranLower ConvertType.cpp + ComplexExpr.cpp OpenMP.cpp PFTBuilder.cpp diff --git a/flang/lib/Lower/ComplexExpr.cpp b/flang/lib/Lower/ComplexExpr.cpp new file mode 100644 index 0000000..1a66c95 --- /dev/null +++ b/flang/lib/Lower/ComplexExpr.cpp @@ -0,0 +1,58 @@ +//===-- ComplexExpr.cpp ---------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "flang/Lower/ComplexExpr.h" +#include "flang/Lower/ConvertType.h" + +//===----------------------------------------------------------------------===// +// ComplexExprHelper implementation +//===----------------------------------------------------------------------===// + +mlir::Type +Fortran::lower::ComplexExprHelper::getComplexPartType(mlir::Type complexType) { + return Fortran::lower::convertReal( + builder.getContext(), complexType.cast().getFKind()); +} + +mlir::Type +Fortran::lower::ComplexExprHelper::getComplexPartType(mlir::Value cplx) { + return getComplexPartType(cplx.getType()); +} + +mlir::Value Fortran::lower::ComplexExprHelper::createComplex(fir::KindTy kind, + mlir::Value real, + mlir::Value imag) { + auto complexTy = fir::CplxType::get(builder.getContext(), kind); + mlir::Value und = builder.create(loc, complexTy); + return insert(insert(und, real), imag); +} + +mlir::Value Fortran::lower::ComplexExprHelper::createComplex(mlir::Type cplxTy, + mlir::Value real, + mlir::Value imag) { + mlir::Value und = builder.create(loc, cplxTy); + return insert(insert(und, real), imag); +} + +mlir::Value Fortran::lower::ComplexExprHelper::createComplexCompare( + mlir::Value cplx1, mlir::Value cplx2, bool eq) { + auto real1 = extract(cplx1); + auto real2 = extract(cplx2); + auto imag1 = extract(cplx1); + auto imag2 = extract(cplx2); + + mlir::CmpFPredicate predicate = + eq ? mlir::CmpFPredicate::UEQ : mlir::CmpFPredicate::UNE; + mlir::Value realCmp = + builder.create(loc, predicate, real1, real2); + mlir::Value imagCmp = + builder.create(loc, predicate, imag1, imag2); + + return eq ? builder.create(loc, realCmp, imagCmp).getResult() + : builder.create(loc, realCmp, imagCmp).getResult(); +}