[flang-commits] [flang] 8bba0bc - [flang] Add the complex expression helper class.

Eric Schweitz via flang-commits flang-commits at lists.llvm.org
Wed Jun 10 09:05:35 PDT 2020


Author: Eric Schweitz
Date: 2020-06-10T09:05:20-07:00
New Revision: 8bba0bca721d66a63709d427ff1e3b48cf7c2cad

URL: https://github.com/llvm/llvm-project/commit/8bba0bca721d66a63709d427ff1e3b48cf7c2cad
DIFF: https://github.com/llvm/llvm-project/commit/8bba0bca721d66a63709d427ff1e3b48cf7c2cad.diff

LOG: [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

Added: 
    flang/include/flang/Lower/ComplexExpr.h
    flang/include/flang/Lower/FIRBuilder.h
    flang/lib/Lower/ComplexExpr.cpp

Modified: 
    flang/lib/Lower/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/ComplexExpr.h b/flang/include/flang/Lower/ComplexExpr.h
new file mode 100644
index 000000000000..d3600a0cda6a
--- /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<Part::Imag>(cplx) : extract<Part::Real>(cplx);
+  }
+
+  /// Returns (Real, Imag) pair of \p cplx
+  std::pair<mlir::Value, mlir::Value> extractParts(mlir::Value cplx) {
+    return {extract<Part::Real>(cplx), extract<Part::Imag>(cplx)};
+  }
+
+  mlir::Value insertComplexPart(mlir::Value cplx, mlir::Value part,
+                                bool isImagPart) {
+    return isImagPart ? insert<Part::Imag>(cplx, part)
+                      : insert<Part::Real>(cplx, part);
+  }
+
+  mlir::Value createComplexCompare(mlir::Value cplx1, mlir::Value cplx2,
+                                   bool eq);
+
+protected:
+  template <Part partId>
+  mlir::Value extract(mlir::Value cplx) {
+    return builder.create<fir::ExtractValueOp>(loc, getComplexPartType(cplx),
+                                               cplx, createPartId<partId>());
+  }
+
+  template <Part partId>
+  mlir::Value insert(mlir::Value cplx, mlir::Value part) {
+    return builder.create<fir::InsertValueOp>(loc, cplx.getType(), cplx, part,
+                                              createPartId<partId>());
+  }
+
+  template <Part partId>
+  mlir::Value createPartId() {
+    return builder.createIntegerConstant(loc, builder.getIndexType(),
+                                         static_cast<int>(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 000000000000..f1fb15048c95
--- /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<mlir::ModuleOp>();
+  }
+
+  /// Get the current Function
+  mlir::FuncOp getFunction() {
+    return getRegion().getParentOfType<mlir::FuncOp>();
+  }
+
+  /// 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<mlir::Value> 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<mlir::Value> shape = {});
+
+  /// Create an unnamed and untracked temporary on the stack.
+  mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
+                              llvm::ArrayRef<mlir::Value> 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<void(FirOpBuilder &)> 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<void(FirOpBuilder &)> 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 4473a13e986b..321fb65fbe4f 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 000000000000..1a66c95f8ed8
--- /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<fir::CplxType>().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<fir::UndefOp>(loc, complexTy);
+  return insert<Part::Imag>(insert<Part::Real>(und, real), imag);
+}
+
+mlir::Value Fortran::lower::ComplexExprHelper::createComplex(mlir::Type cplxTy,
+                                                             mlir::Value real,
+                                                             mlir::Value imag) {
+  mlir::Value und = builder.create<fir::UndefOp>(loc, cplxTy);
+  return insert<Part::Imag>(insert<Part::Real>(und, real), imag);
+}
+
+mlir::Value Fortran::lower::ComplexExprHelper::createComplexCompare(
+    mlir::Value cplx1, mlir::Value cplx2, bool eq) {
+  auto real1 = extract<Part::Real>(cplx1);
+  auto real2 = extract<Part::Real>(cplx2);
+  auto imag1 = extract<Part::Imag>(cplx1);
+  auto imag2 = extract<Part::Imag>(cplx2);
+
+  mlir::CmpFPredicate predicate =
+      eq ? mlir::CmpFPredicate::UEQ : mlir::CmpFPredicate::UNE;
+  mlir::Value realCmp =
+      builder.create<mlir::CmpFOp>(loc, predicate, real1, real2);
+  mlir::Value imagCmp =
+      builder.create<mlir::CmpFOp>(loc, predicate, imag1, imag2);
+
+  return eq ? builder.create<mlir::AndOp>(loc, realCmp, imagCmp).getResult()
+            : builder.create<mlir::OrOp>(loc, realCmp, imagCmp).getResult();
+}


        


More information about the flang-commits mailing list