[flang] Add an enum attribute to carry Fortran attributes
authorJean Perier <jperier@nvidia.com>
Mon, 17 Oct 2022 13:40:39 +0000 (15:40 +0200)
committerJean Perier <jperier@nvidia.com>
Mon, 17 Oct 2022 13:42:42 +0000 (15:42 +0200)
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

flang/include/flang/Optimizer/Dialect/CMakeLists.txt
flang/include/flang/Optimizer/Dialect/FIRAttr.h
flang/include/flang/Optimizer/Dialect/FIRAttr.td [new file with mode: 0644]
flang/lib/Optimizer/Dialect/FIRAttr.cpp
flang/test/Fir/fir-ops.fir
flang/test/Fir/invalid.fir

index 19d14b7..8946856 100644 (file)
@@ -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)
index 20c8210..92b3f7a 100644 (file)
@@ -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 (file)
index 0000000..e6195f8
--- /dev/null
@@ -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<string name> : AttrDef<fir_Dialect, name>;
+
+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
index 4474a1e..655a568 100644 (file)
 #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<ClosedIntervalAttr, ExactTypeAttr, LowerBoundAttr,
-                PointIntervalAttr, RealAttr, SubclassAttr, UpperBoundAttr>();
+  addAttributes<ClosedIntervalAttr, ExactTypeAttr, FortranVariableFlagsAttr,
+                LowerBoundAttr, PointIntervalAttr, RealAttr, SubclassAttr,
+                UpperBoundAttr>();
 }
index 42d05b2..5052a06 100644 (file)
@@ -850,3 +850,35 @@ func.func @embox_tdesc(%arg0: !fir.class<!fir.array<10x!fir.type<derived_poly{a:
   fir.store %4#1 to %0 : !fir.ref<i32>
   return
 }
+
+func.func @test_fortran_var_attrs() {
+  %0 = fir.alloca !fir.heap<f32> {fortran_attrs = #fir.var_attrs<allocatable>}
+  %1 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<asynchronous>}
+  %2 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<bind_c>}
+  %3 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<contiguous>}
+  %4 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<intent_in>}
+  %5 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<intent_inout>}
+  %6 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<intent_out>}
+  %7 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<optional>}
+  %8 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<parameter>}
+  %9 = fir.alloca !fir.ptr<f32> {fortran_attrs = #fir.var_attrs<pointer>}
+  %10 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<target>}
+  %11 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<value>}
+  %12 = fir.alloca f32 {fortran_attrs = #fir.var_attrs<volatile>}
+  %13 = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>> {fortran_attrs = #fir.var_attrs<pointer, contiguous, volatile>}
+  return
+  // CHECK: fir.alloca !fir.heap<f32> {fortran_attrs = #fir.var_attrs<allocatable>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<asynchronous>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<bind_c>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<contiguous>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<intent_in>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<intent_inout>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<intent_out>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<optional>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<parameter>}
+  // CHECK: fir.alloca !fir.ptr<f32> {fortran_attrs = #fir.var_attrs<pointer>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<target>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<value>}
+  // CHECK: fir.alloca f32 {fortran_attrs = #fir.var_attrs<volatile>}
+  // CHECK: fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>> {fortran_attrs = #fir.var_attrs<contiguous, pointer, volatile>}
+}
index a995d86..f7b23c8 100644 (file)
@@ -802,3 +802,9 @@ func.func private @dispatch(%arg0: !fir.class<!fir.type<derived{a:i32,b:i32}>>,
   fir.dispatch "proc1"(%arg0 : !fir.class<!fir.type<derived{a:i32,b:i32}>>) (%arg0, %arg1 : !fir.class<!fir.type<derived{a:i32,b:i32}>>, 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<volatypo>}
+}