[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
This commit is contained in:
Jean Perier 2022-10-21 13:10:52 +02:00
parent a0549ee2a3
commit 451b1b1ffb
14 changed files with 245 additions and 5 deletions

View File

@ -1,3 +1,4 @@
add_subdirectory(CodeGen)
add_subdirectory(Dialect)
add_subdirectory(HLFIR)
add_subdirectory(Transforms)

View File

@ -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)

View File

@ -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

View File

@ -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<hlfir_Dialect, "Expr"> {
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<int64_t>;
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

View File

@ -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 \

View File

@ -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

View File

@ -1,5 +1,6 @@
add_subdirectory(Builder)
add_subdirectory(CodeGen)
add_subdirectory(Dialect)
add_subdirectory(HLFIR)
add_subdirectory(Support)
add_subdirectory(Transforms)

View File

@ -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
)

View File

@ -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 << '>';
}

View File

@ -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<!fir.char<1,?>>
func.func private @scalar02() -> !hlfir.expr<!fir.char<2,10>>
func.func private @scalar03() -> !hlfir.expr<!fir.type<derived{f:f32}>>
// CHECK-LABEL: func.func private @scalar01() -> !hlfir.expr<!fir.char<1,?>>
// CHECK-LABEL: func.func private @scalar02() -> !hlfir.expr<!fir.char<2,10>>
// CHECK-LABEL: func.func private @scalar03() -> !hlfir.expr<!fir.type<derived{f:f32}>>
// Array expression types
func.func private @array01() -> !hlfir.expr<?x!fir.char<1,?>>
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<derived{f:f32}>>
func.func private @array05() -> !hlfir.expr<10xi32>
// CHECK-LABEL: func.func private @array01() -> !hlfir.expr<?x!fir.char<1,?>>
// 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<derived{f:f32}>>
// CHECK-LABEL: func.func private @array05() -> !hlfir.expr<10xi32>
// Polymorphic expression types
func.func private @polymorph01() -> !hlfir.expr<!fir.type<derived{f:f32}>?>
func.func private @polymorph02() -> !hlfir.expr<?x!fir.type<derived{f:f32}>?>
func.func private @polymorph03() -> !hlfir.expr<10x!fir.type<derived{f:f32}>?>
// CHECK-LABEL: func.func private @polymorph01() -> !hlfir.expr<!fir.type<derived{f:f32}>?>
// CHECK-LABEL: func.func private @polymorph02() -> !hlfir.expr<?x!fir.type<derived{f:f32}>?>
// CHECK-LABEL: func.func private @polymorph03() -> !hlfir.expr<10x!fir.type<derived{f:f32}>?>

View File

@ -11,6 +11,7 @@ FIRDialect
FIRSupport
FIRTransforms
FIRBuilder
HLFIRDialect
${dialect_libs}
MLIRAffineToStandard
MLIRSCFToControlFlow

View File

@ -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

View File

@ -7,6 +7,7 @@ target_link_libraries(tco PRIVATE
FIRSupport
FIRTransforms
FIRBuilder
HLFIRDialect
${dialect_libs}
MLIRIR
MLIRLLVMDialect

View File

@ -5,6 +5,7 @@ set(LIBS
FIRCodeGen
FIRDialect
FIRSupport
HLFIRDialect
${dialect_libs}
)