diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt --- 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 --- a/flang/include/flang/Optimizer/Dialect/FIRAttr.h +++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.h @@ -142,4 +142,9 @@ } // 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 --- /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 --- 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 @@ 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 @@ // 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 @@ 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 FIROpsDialect::registerAttributes() { - addAttributes(); + addAttributes(); } diff --git a/flang/test/Fir/fir-ops.fir b/flang/test/Fir/fir-ops.fir --- a/flang/test/Fir/fir-ops.fir +++ b/flang/test/Fir/fir-ops.fir @@ -850,3 +850,35 @@ fir.store %4#1 to %0 : !fir.ref 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 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -802,3 +802,9 @@ 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} +}