diff --git a/flang/include/flang/Optimizer/CMakeLists.txt b/flang/include/flang/Optimizer/CMakeLists.txt --- 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 --- /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 --- /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 --- /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 --- 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 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -17,6 +17,7 @@ FIRDialect FIRSupport FIROptTransformsPassIncGen + HLFIRDialect MLIRIR ${dialect_libs} @@ -33,6 +34,7 @@ FIRBuilder FIRCodeGen FIRTransforms + HLFIRDialect MLIRTransforms MLIRLLVMToLLVMIRTranslation MLIRSCFToControlFlow diff --git a/flang/lib/Optimizer/CMakeLists.txt b/flang/lib/Optimizer/CMakeLists.txt --- 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 --- /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 --- /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 --- /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 --- a/flang/tools/bbc/CMakeLists.txt +++ b/flang/tools/bbc/CMakeLists.txt @@ -11,6 +11,7 @@ FIRSupport FIRTransforms FIRBuilder +HLFIRDialect ${dialect_libs} MLIRAffineToStandard MLIRSCFToControlFlow diff --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt --- a/flang/tools/fir-opt/CMakeLists.txt +++ b/flang/tools/fir-opt/CMakeLists.txt @@ -7,6 +7,7 @@ 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 --- a/flang/tools/tco/CMakeLists.txt +++ b/flang/tools/tco/CMakeLists.txt @@ -7,6 +7,7 @@ FIRSupport FIRTransforms FIRBuilder + HLFIRDialect ${dialect_libs} MLIRIR MLIRLLVMDialect diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt --- a/flang/unittests/Optimizer/CMakeLists.txt +++ b/flang/unittests/Optimizer/CMakeLists.txt @@ -5,6 +5,7 @@ FIRCodeGen FIRDialect FIRSupport + HLFIRDialect ${dialect_libs} )