From 451b1b1ffbb655fdebaea5bc2a508d60e16ca22e Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Fri, 21 Oct 2022 13:10:52 +0200 Subject: [PATCH] [flang] Add High level Fortran IR dialect This patch adds the basic dialect definition of the HLFIR dialect that was described in https://reviews.llvm.org/D134285. It adds the definition of the hlfir.expr type and related tests so that it can be verified that the dialect is properly hooked up by the tools. Operations will be added as progress is made in the expression lowering update. Differential Revision: https://reviews.llvm.org/D136328 --- flang/include/flang/Optimizer/CMakeLists.txt | 1 + .../flang/Optimizer/HLFIR/CMakeLists.txt | 8 ++ .../flang/Optimizer/HLFIR/HLFIRDialect.h | 27 +++++++ .../flang/Optimizer/HLFIR/HLFIROpBase.td | 73 +++++++++++++++++++ .../include/flang/Optimizer/Support/InitFIR.h | 11 +-- flang/lib/Frontend/CMakeLists.txt | 2 + flang/lib/Optimizer/CMakeLists.txt | 1 + flang/lib/Optimizer/HLFIR/CMakeLists.txt | 20 +++++ flang/lib/Optimizer/HLFIR/HLFIRDialect.cpp | 72 ++++++++++++++++++ flang/test/HLFIR/expr-type.fir | 31 ++++++++ flang/tools/bbc/CMakeLists.txt | 1 + flang/tools/fir-opt/CMakeLists.txt | 1 + flang/tools/tco/CMakeLists.txt | 1 + flang/unittests/Optimizer/CMakeLists.txt | 1 + 14 files changed, 245 insertions(+), 5 deletions(-) create mode 100644 flang/include/flang/Optimizer/HLFIR/CMakeLists.txt create mode 100644 flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h create mode 100644 flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td create mode 100644 flang/lib/Optimizer/HLFIR/CMakeLists.txt create mode 100644 flang/lib/Optimizer/HLFIR/HLFIRDialect.cpp create mode 100644 flang/test/HLFIR/expr-type.fir diff --git a/flang/include/flang/Optimizer/CMakeLists.txt b/flang/include/flang/Optimizer/CMakeLists.txt index 0fa521d5b967..89e43a9ee8d6 100644 --- a/flang/include/flang/Optimizer/CMakeLists.txt +++ b/flang/include/flang/Optimizer/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(CodeGen) add_subdirectory(Dialect) +add_subdirectory(HLFIR) add_subdirectory(Transforms) diff --git a/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt b/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt new file mode 100644 index 000000000000..35fda6d1610e --- /dev/null +++ b/flang/include/flang/Optimizer/HLFIR/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_TARGET_DEFINITIONS HLFIROpBase.td) +mlir_tablegen(HLFIRTypes.h.inc -gen-typedef-decls) +mlir_tablegen(HLFIRTypes.cpp.inc -gen-typedef-defs) +mlir_tablegen(HLFIRDialect.h.inc -gen-dialect-decls -dialect=hlfir) +mlir_tablegen(HLFIRDialect.cpp.inc -gen-dialect-defs -dialect=hlfir) +mlir_tablegen(HLFIRAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=hlfir) +mlir_tablegen(HLFIRAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=hlfir) +add_public_tablegen_target(HLFIROpsIncGen) diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h new file mode 100644 index 000000000000..2e7f615065ab --- /dev/null +++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h @@ -0,0 +1,27 @@ +//===- HLFIRDialect.h - High Level Fortran IR dialect -----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the HLFIR dialect that models Fortran expressions and +// assignments without requiring storage allocation and manipulations. +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_HLFIR_HLFIRDIALECT_H +#define FORTRAN_OPTIMIZER_HLFIR_HLFIRDIALECT_H + +#include "mlir/IR/Dialect.h" + +#include "flang/Optimizer/HLFIR/HLFIRDialect.h.inc" + +#define GET_TYPEDEF_CLASSES +#include "flang/Optimizer/HLFIR/HLFIRTypes.h.inc" + +#define GET_ATTRDEF_CLASSES +#include "flang/Optimizer/HLFIR/HLFIRAttributes.h.inc" + +#endif // FORTRAN_OPTIMIZER_HLFIR_HLFIRDIALECT_H diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td new file mode 100644 index 000000000000..9b3578c40684 --- /dev/null +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROpBase.td @@ -0,0 +1,73 @@ +//===-- HLFIROpBase.td - HLFIR dialect base definitions ----*- tablegen -*-===// +// +// 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 +/// Definition of the HLFIR dialect and core hlfir.expr type +/// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_DIALECT_HLFIR_OP_BASE +#define FORTRAN_DIALECT_HLFIR_OP_BASE + +include "mlir/IR/AttrTypeBase.td" +include "mlir/IR/OpBase.td" + +def hlfir_Dialect : Dialect { + let name = "hlfir"; + + let summary = "High Level Fortran IR."; + + let description = [{ + This dialect models Fortran expressions and assignments without requiring + the allocation and manipulation of temporary storage. + It allows running high level optimization passes and is rather + straightforward to generate from Fortran expressions and assignments. + + It is not a complete implementation of Fortran, for constructs and lower + level operations, FIR should be used directly. + + A bufferization pass transforms hlfir.expr values into FIR temporary in + memory, and its translation pass to FIR translates high level operations + into sequence of lower level FIR operations operating on memory. + }]; + + let useDefaultTypePrinterParser = 1; + let cppNamespace = "hlfir"; +} + + +def hlfir_ExprType : TypeDef { + let mnemonic = "expr"; + let summary = "The type of an array, character, or derived type Fortran expression"; + + let description = [{ + Abstract value type for Fortran arrays, characters and derived types. + The rank cannot be assumed, and empty shape means that the expression is a scalar. + When the element type is a derived type, the polymorphic flag may be set to true + to indicate that the expression dynamic type can differ from its static type. + }]; + + + let parameters = (ins + ArrayRefParameter<"int64_t", "expression shape">:$shape, + "mlir::Type":$elementType, + "bool":$polymorphic + ); + + let extraClassDeclaration = [{ + using Shape = llvm::SmallVector; + mlir::Type getEleTy() const {return getElementType();} + bool isArray() const { return !getShape().empty(); } + bool isPolymorphic() const { return getPolymorphic(); } + }]; + + let hasCustomAssemblyFormat = 1; + +} + +#endif // FORTRAN_DIALECT_HLFIR_OP_BASE diff --git a/flang/include/flang/Optimizer/Support/InitFIR.h b/flang/include/flang/Optimizer/Support/InitFIR.h index 77344f740790..434556edb32e 100644 --- a/flang/include/flang/Optimizer/Support/InitFIR.h +++ b/flang/include/flang/Optimizer/Support/InitFIR.h @@ -14,6 +14,7 @@ #define FORTRAN_OPTIMIZER_SUPPORT_INITFIR_H #include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/HLFIR/HLFIRDialect.h" #include "mlir/Conversion/Passes.h" #include "mlir/Dialect/Affine/Passes.h" #include "mlir/InitAllDialects.h" @@ -25,11 +26,11 @@ namespace fir::support { #define FLANG_NONCODEGEN_DIALECT_LIST \ - mlir::AffineDialect, FIROpsDialect, mlir::acc::OpenACCDialect, \ - mlir::omp::OpenMPDialect, mlir::scf::SCFDialect, \ - mlir::arith::ArithDialect, mlir::cf::ControlFlowDialect, \ - mlir::func::FuncDialect, mlir::vector::VectorDialect, \ - mlir::math::MathDialect + mlir::AffineDialect, FIROpsDialect, hlfir::hlfirDialect, \ + mlir::acc::OpenACCDialect, mlir::omp::OpenMPDialect, \ + mlir::scf::SCFDialect, mlir::arith::ArithDialect, \ + mlir::cf::ControlFlowDialect, mlir::func::FuncDialect, \ + mlir::vector::VectorDialect, mlir::math::MathDialect // The definitive list of dialects used by flang. #define FLANG_DIALECT_LIST \ diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index 96769c707f10..fbe302447980 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -17,6 +17,7 @@ add_flang_library(flangFrontend FIRDialect FIRSupport FIROptTransformsPassIncGen + HLFIRDialect MLIRIR ${dialect_libs} @@ -33,6 +34,7 @@ add_flang_library(flangFrontend FIRBuilder FIRCodeGen FIRTransforms + HLFIRDialect MLIRTransforms MLIRLLVMToLLVMIRTranslation MLIRSCFToControlFlow diff --git a/flang/lib/Optimizer/CMakeLists.txt b/flang/lib/Optimizer/CMakeLists.txt index d2da0f98611a..2320bf4f4427 100644 --- a/flang/lib/Optimizer/CMakeLists.txt +++ b/flang/lib/Optimizer/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(Builder) add_subdirectory(CodeGen) add_subdirectory(Dialect) +add_subdirectory(HLFIR) add_subdirectory(Support) add_subdirectory(Transforms) diff --git a/flang/lib/Optimizer/HLFIR/CMakeLists.txt b/flang/lib/Optimizer/HLFIR/CMakeLists.txt new file mode 100644 index 000000000000..890bc52cc845 --- /dev/null +++ b/flang/lib/Optimizer/HLFIR/CMakeLists.txt @@ -0,0 +1,20 @@ +get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) + +add_flang_library(HLFIRDialect + HLFIRDialect.cpp + + DEPENDS + FIRDialect + HLFIROpsIncGen + ${dialect_libs} + + LINK_LIBS + FIRDialect + MLIRIR + ${dialect_libs} + + LINK_COMPONENTS + AsmParser + AsmPrinter + Remarks +) diff --git a/flang/lib/Optimizer/HLFIR/HLFIRDialect.cpp b/flang/lib/Optimizer/HLFIR/HLFIRDialect.cpp new file mode 100644 index 000000000000..a6406992948a --- /dev/null +++ b/flang/lib/Optimizer/HLFIR/HLFIRDialect.cpp @@ -0,0 +1,72 @@ +//===-- HLFIRDialect.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 +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/HLFIR/HLFIRDialect.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/DialectImplementation.h" +#include "mlir/IR/Matchers.h" +#include "mlir/IR/OpImplementation.h" +#include "llvm/ADT/TypeSwitch.h" + +#include "flang/Optimizer/HLFIR/HLFIRDialect.cpp.inc" + +#define GET_TYPEDEF_CLASSES +#include "flang/Optimizer/HLFIR/HLFIRTypes.cpp.inc" + +#define GET_ATTRDEF_CLASSES +#include "flang/Optimizer/HLFIR/HLFIRAttributes.cpp.inc" + +void hlfir::hlfirDialect::initialize() { + addTypes< +#define GET_TYPEDEF_LIST +#include "flang/Optimizer/HLFIR/HLFIRTypes.cpp.inc" + >(); +} + +// `expr` `<` `*` | bounds (`x` bounds)* `:` type [`?`] `>` +// bounds ::= `?` | int-lit +mlir::Type hlfir::ExprType::parse(mlir::AsmParser &parser) { + if (parser.parseLess()) + return {}; + ExprType::Shape shape; + if (parser.parseOptionalStar()) { + if (parser.parseDimensionList(shape, /*allowDynamic=*/true)) + return {}; + } else if (parser.parseColon()) { + return {}; + } + mlir::Type eleTy; + if (parser.parseType(eleTy)) + return {}; + const bool polymorphic = mlir::succeeded(parser.parseOptionalQuestion()); + if (parser.parseGreater()) + return {}; + return ExprType::get(parser.getContext(), shape, eleTy, polymorphic); +} + +void hlfir::ExprType::print(mlir::AsmPrinter &printer) const { + auto shape = getShape(); + printer << '<'; + if (shape.size()) { + for (const auto &b : shape) { + if (b >= 0) + printer << b << 'x'; + else + printer << "?x"; + } + } + printer << getEleTy(); + if (isPolymorphic()) + printer << '?'; + printer << '>'; +} diff --git a/flang/test/HLFIR/expr-type.fir b/flang/test/HLFIR/expr-type.fir new file mode 100644 index 000000000000..835959ce5464 --- /dev/null +++ b/flang/test/HLFIR/expr-type.fir @@ -0,0 +1,31 @@ +// Test the HLFIR Expr type +// Parse types and check that we can reparse what we print. +// RUN: fir-opt --split-input-file %s | fir-opt --split-input-file | FileCheck %s + +// Scalar expression types +func.func private @scalar01() -> !hlfir.expr> +func.func private @scalar02() -> !hlfir.expr> +func.func private @scalar03() -> !hlfir.expr> +// CHECK-LABEL: func.func private @scalar01() -> !hlfir.expr> +// CHECK-LABEL: func.func private @scalar02() -> !hlfir.expr> +// CHECK-LABEL: func.func private @scalar03() -> !hlfir.expr> + +// Array expression types +func.func private @array01() -> !hlfir.expr> +func.func private @array02() -> !hlfir.expr<10x!fir.char<1,20>> +func.func private @array03() -> !hlfir.expr<10x?x20x?x30x?x40x?x50x?x60xf128> +func.func private @array04() -> !hlfir.expr<10x20x!fir.type> +func.func private @array05() -> !hlfir.expr<10xi32> +// CHECK-LABEL: func.func private @array01() -> !hlfir.expr> +// CHECK-LABEL: func.func private @array02() -> !hlfir.expr<10x!fir.char<1,20>> +// CHECK-LABEL: func.func private @array03() -> !hlfir.expr<10x?x20x?x30x?x40x?x50x?x60xf128> +// CHECK-LABEL: func.func private @array04() -> !hlfir.expr<10x20x!fir.type> +// CHECK-LABEL: func.func private @array05() -> !hlfir.expr<10xi32> + +// Polymorphic expression types +func.func private @polymorph01() -> !hlfir.expr?> +func.func private @polymorph02() -> !hlfir.expr?> +func.func private @polymorph03() -> !hlfir.expr<10x!fir.type?> +// CHECK-LABEL: func.func private @polymorph01() -> !hlfir.expr?> +// CHECK-LABEL: func.func private @polymorph02() -> !hlfir.expr?> +// CHECK-LABEL: func.func private @polymorph03() -> !hlfir.expr<10x!fir.type?> diff --git a/flang/tools/bbc/CMakeLists.txt b/flang/tools/bbc/CMakeLists.txt index 5830531dff78..4c50d629197b 100644 --- a/flang/tools/bbc/CMakeLists.txt +++ b/flang/tools/bbc/CMakeLists.txt @@ -11,6 +11,7 @@ FIRDialect FIRSupport FIRTransforms FIRBuilder +HLFIRDialect ${dialect_libs} MLIRAffineToStandard MLIRSCFToControlFlow diff --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt index 8bed259e049b..adbdb23739dd 100644 --- a/flang/tools/fir-opt/CMakeLists.txt +++ b/flang/tools/fir-opt/CMakeLists.txt @@ -7,6 +7,7 @@ target_link_libraries(fir-opt PRIVATE FIRSupport FIRTransforms FIRCodeGen + HLFIRDialect ${dialect_libs} # TODO: these should be transitive dependencies from a target providing diff --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt index 329c3864f3fe..e78124996b7d 100644 --- a/flang/tools/tco/CMakeLists.txt +++ b/flang/tools/tco/CMakeLists.txt @@ -7,6 +7,7 @@ target_link_libraries(tco PRIVATE FIRSupport FIRTransforms FIRBuilder + HLFIRDialect ${dialect_libs} MLIRIR MLIRLLVMDialect diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt index e23f0cfe39ee..c3cc04e86ce2 100644 --- a/flang/unittests/Optimizer/CMakeLists.txt +++ b/flang/unittests/Optimizer/CMakeLists.txt @@ -5,6 +5,7 @@ set(LIBS FIRCodeGen FIRDialect FIRSupport + HLFIRDialect ${dialect_libs} )