From c4331358fb9de83289b2638a77e8e08e41f56860 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Mon, 17 Oct 2022 15:40:39 +0200 Subject: [PATCH] [flang] Add an enum attribute to carry Fortran attributes Currently, Fortran attributes are mostly represented via the presence of named attribute with special names (fir.target, fir.contiguous, fir.optional...). Create an enum so that these attributes can be more easily and safely manipulated in FIR. This patch does not add usages for it yet. It is planned to use in it in the future HLFIR and fir.declare operations. This is added to FIR and not HLFIR because it is intended to be used on fir.declare that will be part of FIR, and seems also usefull for FIR operations. Differential Revision: https://reviews.llvm.org/D135961 --- .../include/flang/Optimizer/Dialect/CMakeLists.txt | 6 +++ flang/include/flang/Optimizer/Dialect/FIRAttr.h | 5 ++ flang/include/flang/Optimizer/Dialect/FIRAttr.td | 60 ++++++++++++++++++++++ flang/lib/Optimizer/Dialect/FIRAttr.cpp | 59 ++++++++++++++++++--- flang/test/Fir/fir-ops.fir | 32 ++++++++++++ flang/test/Fir/invalid.fir | 6 +++ 6 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 flang/include/flang/Optimizer/Dialect/FIRAttr.td diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt index 19d14b7..8946856 100644 --- a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt +++ b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt @@ -1,6 +1,12 @@ # This replicates part of the add_mlir_dialect cmake function from MLIR that # cannot be used her because it expects to be run inside MLIR directory which # is not the case for FIR. +set(LLVM_TARGET_DEFINITIONS FIRAttr.td) +mlir_tablegen(FIREnumAttr.h.inc -gen-enum-decls) +mlir_tablegen(FIREnumAttr.cpp.inc -gen-enum-defs) +mlir_tablegen(FIRAttr.h.inc --gen-attrdef-decls) +mlir_tablegen(FIRAttr.cpp.inc -gen-attrdef-defs) + set(LLVM_TARGET_DEFINITIONS FIROps.td) mlir_tablegen(FIROps.h.inc -gen-op-decls) mlir_tablegen(FIROps.cpp.inc -gen-op-defs) diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.h b/flang/include/flang/Optimizer/Dialect/FIRAttr.h index 20c8210..92b3f7a 100644 --- a/flang/include/flang/Optimizer/Dialect/FIRAttr.h +++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.h @@ -142,4 +142,9 @@ void printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr, } // namespace fir +#include "flang/Optimizer/Dialect/FIREnumAttr.h.inc" + +#define GET_ATTRDEF_CLASSES +#include "flang/Optimizer/Dialect/FIRAttr.h.inc" + #endif // FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td new file mode 100644 index 0000000..e6195f8 --- /dev/null +++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td @@ -0,0 +1,60 @@ +//===- FIRAttr.td - FIR Attributes -------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the FIR dialect attributes. +// +//===----------------------------------------------------------------------===// + +#ifndef FIR_DIALECT_FIR_ATTRS +#define FIR_DIALECT_FIR_ATTRS + +include "flang/Optimizer/Dialect/FIRDialect.td" +include "mlir/IR/EnumAttr.td" + +class fir_Attr : AttrDef; + +def FIRnoAttributes : I32BitEnumAttrCaseNone<"None">; +def FIRallocatable : I32BitEnumAttrCaseBit<"allocatable", 0>; +def FIRasynchronous : I32BitEnumAttrCaseBit<"asynchronous", 1>; +def FIRbind_c : I32BitEnumAttrCaseBit<"bind_c", 2>; +def FIRcontiguous : I32BitEnumAttrCaseBit<"contiguous", 3>; +def FIRintent_in : I32BitEnumAttrCaseBit<"intent_in", 4>; +def FIRintent_inout : I32BitEnumAttrCaseBit<"intent_inout", 5>; +def FIRintent_out : I32BitEnumAttrCaseBit<"intent_out", 6>; +def FIRoptional : I32BitEnumAttrCaseBit<"optional", 7>; +def FIRparameter : I32BitEnumAttrCaseBit<"parameter", 8>; +def FIRpointer : I32BitEnumAttrCaseBit<"pointer", 9>; +def FIRtarget : I32BitEnumAttrCaseBit<"target", 10>; +def FIRvalue : I32BitEnumAttrCaseBit<"value", 11>; +def FIRvolatile : I32BitEnumAttrCaseBit<"fortran_volatile", 12, "volatile">; + +def fir_FortranVariableFlagsEnum : I32BitEnumAttr< + "FortranVariableFlagsEnum", + "Fortran variable attributes", + [FIRnoAttributes, FIRallocatable, FIRasynchronous, FIRbind_c, FIRcontiguous, + FIRintent_in, FIRintent_inout, FIRintent_out, FIRoptional, FIRparameter, + FIRpointer, FIRtarget, FIRvalue, FIRvolatile]> { + let separator = ", "; + let cppNamespace = "::fir"; + let printBitEnumPrimaryGroups = 1; +} + +def fir_FortranVariableFlagsAttr : fir_Attr<"FortranVariableFlags"> { + let mnemonic = "var_attrs"; + + let parameters = (ins + "FortranVariableFlagsEnum":$flags + ); + let hasCustomAssemblyFormat = 1; + let returnType = "::fir::FortranVariableFlagsEnum"; + let convertFromStorage = "$_self.getFlags()"; + let constBuilderCall = + "::fir::FortranVariableFlagsAttr::get($_builder.getContext(), $0)"; +} + +#endif // FIR_DIALECT_FIR_ATTRS diff --git a/flang/lib/Optimizer/Dialect/FIRAttr.cpp b/flang/lib/Optimizer/Dialect/FIRAttr.cpp index 4474a1e..655a568 100644 --- a/flang/lib/Optimizer/Dialect/FIRAttr.cpp +++ b/flang/lib/Optimizer/Dialect/FIRAttr.cpp @@ -17,6 +17,12 @@ #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/DialectImplementation.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/TypeSwitch.h" + +#include "flang/Optimizer/Dialect/FIREnumAttr.cpp.inc" +#define GET_ATTRDEF_CLASSES +#include "flang/Optimizer/Dialect/FIRAttr.cpp.inc" using namespace fir; @@ -171,15 +177,47 @@ static mlir::Attribute parseFirRealAttr(FIROpsDialect *dialect, return RealAttr::get(dialect->getContext(), {kind, value}); } +mlir::Attribute fir::FortranVariableFlagsAttr::parse(mlir::AsmParser &parser, + mlir::Type type) { + if (mlir::failed(parser.parseLess())) + return {}; + + fir::FortranVariableFlagsEnum flags = {}; + if (mlir::failed(parser.parseOptionalGreater())) { + auto parseFlags = [&]() -> mlir::ParseResult { + llvm::StringRef elemName; + if (mlir::failed(parser.parseKeyword(&elemName))) + return mlir::failure(); + + auto elem = fir::symbolizeFortranVariableFlagsEnum(elemName); + if (!elem) + return parser.emitError(parser.getNameLoc(), + "Unknown fortran variable attribute: ") + << elemName; + + flags = flags | *elem; + return mlir::success(); + }; + if (mlir::failed(parser.parseCommaSeparatedList(parseFlags)) || + parser.parseGreater()) + return {}; + } + + return FortranVariableFlagsAttr::get(parser.getContext(), flags); +} + mlir::Attribute fir::parseFirAttribute(FIROpsDialect *dialect, mlir::DialectAsmParser &parser, mlir::Type type) { auto loc = parser.getNameLoc(); llvm::StringRef attrName; - if (parser.parseKeyword(&attrName)) { - parser.emitError(loc, "expected an attribute name"); - return {}; - } + mlir::Attribute attr; + mlir::OptionalParseResult result = + generatedAttributeParser(parser, &attrName, type, attr); + if (result.has_value()) + return attr; + if (attrName.empty()) + return {}; // error reported by generatedAttributeParser if (attrName == ExactTypeAttr::getAttrName()) { mlir::Type type; @@ -216,6 +254,12 @@ mlir::Attribute fir::parseFirAttribute(FIROpsDialect *dialect, // FIR attribute pretty printer //===----------------------------------------------------------------------===// +void fir::FortranVariableFlagsAttr::print(mlir::AsmPrinter &printer) const { + printer << "<"; + printer << fir::stringifyFortranVariableFlagsEnum(this->getFlags()); + printer << ">"; +} + void fir::printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr, mlir::DialectAsmPrinter &p) { auto &os = p.getStream(); @@ -240,7 +284,7 @@ void fir::printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr, llvm::SmallString<40> ss; a.getValue().bitcastToAPInt().toStringUnsigned(ss, 16); os << ss << '>'; - } else { + } else if (mlir::failed(generatedAttributePrinter(attr, p))) { // don't know how to print the attribute, so use a default os << "<(unknown attribute)>"; } @@ -251,6 +295,7 @@ void fir::printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr, //===----------------------------------------------------------------------===// void FIROpsDialect::registerAttributes() { - addAttributes(); + addAttributes(); } diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir index 42d05b2..5052a06 100644 --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -850,3 +850,35 @@ func.func @embox_tdesc(%arg0: !fir.class return } + +func.func @test_fortran_var_attrs() { + %0 = fir.alloca !fir.heap {fortran_attrs = #fir.var_attrs} + %1 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %2 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %3 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %4 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %5 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %6 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %7 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %8 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %9 = fir.alloca !fir.ptr {fortran_attrs = #fir.var_attrs} + %10 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %11 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %12 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} + %13 = fir.alloca !fir.box>> {fortran_attrs = #fir.var_attrs} + return + // CHECK: fir.alloca !fir.heap {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca !fir.ptr {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs} + // CHECK: fir.alloca !fir.box>> {fortran_attrs = #fir.var_attrs} +} diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index a995d86..f7b23c8 100644 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -802,3 +802,9 @@ func.func private @dispatch(%arg0: !fir.class>, fir.dispatch "proc1"(%arg0 : !fir.class>) (%arg0, %arg1 : !fir.class>, i32) {pass_arg_pos = 1 : i32} return } + +// ----- +func.func @test_fortran_var_attrs() { + // expected-error@+1 {{Unknown fortran variable attribute: volatypo}} + %0 = fir.alloca f32 {fortran_attrs = #fir.var_attrs} +} -- 2.7.4