[flang-commits] [flang] [mlir] [mlir][acc] add VariableInfo class to thread langauge specific information about privatized variables (PR #186368)
via flang-commits
flang-commits at lists.llvm.org
Mon Mar 30 01:15:36 PDT 2026
https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/186368
>From a566eafe32e5f70bd8227cbbbb599cd2f0492210 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Fri, 13 Mar 2026 03:09:11 -0700
Subject: [PATCH 1/3] [mlir][acc] add VariableInfo class to thread langauge
specific information about privatized variables
---
.../Support/FIROpenACCTypeInterfaces.h | 11 ++-
.../OpenACC/Support/FortranVariableInfo.h | 41 ++++++++++
.../Support/FIROpenACCTypeInterfaces.cpp | 71 +++++++++++++----
.../OpenACC/Support/FIROpenACCUtils.cpp | 14 ++--
mlir/include/mlir/Dialect/OpenACC/OpenACC.h | 1 +
.../mlir/Dialect/OpenACC/OpenACCOps.td | 8 +-
.../Dialect/OpenACC/OpenACCTypeInterfaces.td | 43 +++++++++-
.../Dialect/OpenACC/OpenACCVariableInfo.h | 78 +++++++++++++++++++
mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp | 44 +++++++----
.../OpenACC/Transforms/ACCImplicitData.cpp | 4 +-
.../Dialect/OpenACC/TestRecipePopulate.cpp | 8 +-
11 files changed, 276 insertions(+), 47 deletions(-)
create mode 100644 flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h
create mode 100644 mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
index 9d952a6130f0e..a31d3d9798ff8 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
@@ -80,22 +80,29 @@ struct OpenACCMappableModel
mlir::acc::VariableTypeCategory getTypeCategory(mlir::Type type,
mlir::Value var) const;
+ mlir::acc::VariableInfo
+ genPrivateVariableInfo(mlir::Type type,
+ mlir::TypedValue<mlir::acc::MappableType> var) const;
+
mlir::Value generatePrivateInit(mlir::Type type, mlir::OpBuilder &builder,
mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var,
llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
+ const mlir::acc::VariableInfo &varInfo,
bool &needsDestroy) const;
bool generatePrivateDestroy(mlir::Type type, mlir::OpBuilder &builder,
mlir::Location loc, mlir::Value privatized,
- mlir::ValueRange bounds) const;
+ mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const;
bool generateCopy(mlir::Type type, mlir::OpBuilder &mlirBuilder,
mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> source,
mlir::TypedValue<mlir::acc::MappableType> dest,
- mlir::ValueRange bounds) const;
+ mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const;
bool generateCombiner(mlir::Type type, mlir::OpBuilder &mlirBuilder,
mlir::Location loc,
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h b/flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h
new file mode 100644
index 0000000000000..0b5a9518bd00b
--- /dev/null
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h
@@ -0,0 +1,41 @@
+//===- FortranVariableInfo.h - Fortran variable info for OpenACC -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Fortran-specific variable information carried through the OpenACC type
+// interface helpers (generatePrivateInit, generateCopy,
+// generatePrivateDestroy). This allows recovering properties such as
+// OPTIONAL that are not representable in the FIR type system.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FLANG_OPTIMIZER_OPENACC_FORTRANVARIABLEINFO_H
+#define FLANG_OPTIMIZER_OPENACC_FORTRANVARIABLEINFO_H
+
+#include "mlir/Dialect/OpenACC/OpenACCVariableInfo.h"
+
+namespace fir::acc {
+
+class FortranVariableInfo : public mlir::acc::VariableInfoBase {
+public:
+ explicit FortranVariableInfo(bool mayBeOptional)
+ : VariableInfoBase(Language::Fortran), mayBeOptional_(mayBeOptional) {}
+
+ bool getMayBeOptional() const { return mayBeOptional_; }
+
+ static bool classof(const VariableInfoBase *base) {
+ return base->getLanguage() == Language::Fortran;
+ }
+
+private:
+ bool mayBeOptional_;
+};
+
+} // namespace fir::acc
+
+#endif // FLANG_OPTIMIZER_OPENACC_FORTRANVARIABLEINFO_H
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index 5d427c9aab8ab..697ec33c167b8 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -24,6 +24,7 @@
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
+#include "flang/Optimizer/OpenACC/Support/FortranVariableInfo.h"
#include "flang/Optimizer/Support/Utils.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
@@ -542,6 +543,30 @@ template mlir::acc::VariableTypeCategory
OpenACCMappableModel<fir::PointerType>::getTypeCategory(mlir::Type type,
mlir::Value var) const;
+template <typename Ty>
+mlir::acc::VariableInfo OpenACCMappableModel<Ty>::genPrivateVariableInfo(
+ mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const {
+ hlfir::Entity entity{var};
+ return mlir::acc::VariableInfo(
+ std::make_unique<FortranVariableInfo>(entity.mayBeOptional()));
+}
+
+template mlir::acc::VariableInfo
+OpenACCMappableModel<fir::BaseBoxType>::genPrivateVariableInfo(
+ mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
+
+template mlir::acc::VariableInfo
+OpenACCMappableModel<fir::ReferenceType>::genPrivateVariableInfo(
+ mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
+
+template mlir::acc::VariableInfo
+OpenACCMappableModel<fir::HeapType>::genPrivateVariableInfo(
+ mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
+
+template mlir::acc::VariableInfo
+OpenACCMappableModel<fir::PointerType>::genPrivateVariableInfo(
+ mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
+
static mlir::acc::VariableTypeCategory
categorizePointee(mlir::Type pointer,
mlir::TypedValue<mlir::acc::PointerLikeType> varPtr,
@@ -717,7 +742,8 @@ template <typename Ty>
mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
- mlir::ValueRange bounds, mlir::Value initVal, bool &needsDestroy) const {
+ mlir::ValueRange bounds, mlir::Value initVal,
+ const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const {
mlir::ModuleOp mod = mlirBuilder.getInsertionBlock()
->getParent()
->getParentOfType<mlir::ModuleOp>();
@@ -900,31 +926,35 @@ template mlir::Value
OpenACCMappableModel<fir::BaseBoxType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
- mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const;
+ mlir::ValueRange extents, mlir::Value initVal,
+ const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
template mlir::Value
OpenACCMappableModel<fir::ReferenceType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
- mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const;
+ mlir::ValueRange extents, mlir::Value initVal,
+ const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
template mlir::Value OpenACCMappableModel<fir::HeapType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
- mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const;
+ mlir::ValueRange extents, mlir::Value initVal,
+ const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
template mlir::Value
OpenACCMappableModel<fir::PointerType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
- mlir::ValueRange extents, mlir::Value initVal, bool &needsDestroy) const;
+ mlir::ValueRange extents, mlir::Value initVal,
+ const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
template <typename Ty>
bool OpenACCMappableModel<Ty>::generateCopy(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> src,
- mlir::TypedValue<mlir::acc::MappableType> dest,
- mlir::ValueRange bounds) const {
+ mlir::TypedValue<mlir::acc::MappableType> dest, mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const {
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve parent module");
@@ -961,19 +991,23 @@ bool OpenACCMappableModel<Ty>::generateCopy(
template bool OpenACCMappableModel<fir::BaseBoxType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
- mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
+ mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
+ const mlir::acc::VariableInfo &) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
- mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
+ mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
+ const mlir::acc::VariableInfo &) const;
template bool OpenACCMappableModel<fir::PointerType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
- mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
+ mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
+ const mlir::acc::VariableInfo &) const;
template bool OpenACCMappableModel<fir::HeapType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
- mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange) const;
+ mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
+ const mlir::acc::VariableInfo &) const;
template <typename Op>
static mlir::Value genLogicalCombiner(fir::FirOpBuilder &builder,
@@ -1175,7 +1209,8 @@ template bool OpenACCMappableModel<fir::HeapType>::generateCombiner(
template <typename Ty>
bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds) const {
+ mlir::Value privatized, mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const {
hlfir::Entity inputVar = hlfir::Entity{privatized};
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
@@ -1210,16 +1245,20 @@ bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
template bool OpenACCMappableModel<fir::BaseBoxType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds) const;
+ mlir::Value privatized, mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds) const;
+ mlir::Value privatized, mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const;
template bool OpenACCMappableModel<fir::HeapType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds) const;
+ mlir::Value privatized, mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const;
template bool OpenACCMappableModel<fir::PointerType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Value privatized, mlir::ValueRange bounds) const;
+ mlir::Value privatized, mlir::ValueRange bounds,
+ const mlir::acc::VariableInfo &varInfo) const;
template <typename Ty>
mlir::Value OpenACCPointerLikeModel<Ty>::genAllocate(
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index a53ea9216f7ab..e331d968301fb 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -492,13 +492,15 @@ static RecipeOp genRecipeOp(
auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
assert(mappableTy &&
"Expected that all variable types are considered mappable");
+ auto initArg = mlir::cast<MappableValue>(initBlock->getArgument(0));
+ mlir::acc::VariableInfo varInfo = mappableTy.genPrivateVariableInfo(initArg);
bool needsDestroy = false;
llvm::SmallVector<mlir::Value> initBounds =
getRecipeBounds(builder, loc, dataOperationBounds,
initBlock->getArguments().drop_front(1));
mlir::Value retVal = mappableTy.generatePrivateInit(
- builder, loc, mlir::cast<MappableValue>(initBlock->getArgument(0)),
- initName, initBounds, initValue, needsDestroy);
+ builder, loc, initArg, initName, initBounds, initValue, varInfo,
+ needsDestroy);
mlir::acc::YieldOp::create(builder, loc, retVal);
// Create destroy region and generate destruction if requested.
if (needsDestroy) {
@@ -524,7 +526,7 @@ static RecipeOp genRecipeOp(
getRecipeBounds(builder, loc, dataOperationBounds,
destroyBlock->getArguments().drop_front(2));
[[maybe_unused]] bool success = mappableTy.generatePrivateDestroy(
- builder, loc, destroyBlock->getArgument(1), destroyBounds);
+ builder, loc, destroyBlock->getArgument(1), destroyBounds, varInfo);
assert(success && "failed to generate destroy region");
mlir::acc::TerminatorOp::create(builder, loc);
}
@@ -576,8 +578,10 @@ mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe(
auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
assert(mappableTy &&
"Expected that all variable types are considered mappable");
- [[maybe_unused]] bool success =
- mappableTy.generateCopy(builder, loc, source, destination, copyBounds);
+ mlir::acc::VariableInfo copyVarInfo =
+ mappableTy.genPrivateVariableInfo(source);
+ [[maybe_unused]] bool success = mappableTy.generateCopy(
+ builder, loc, source, destination, copyBounds, copyVarInfo);
assert(success && "failed to generate copy");
mlir::acc::TerminatorOp::create(builder, loc);
return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index 55fc8251a9bbd..9e7a15feb2e70 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -13,6 +13,7 @@
#ifndef MLIR_DIALECT_OPENACC_OPENACC_H_
#define MLIR_DIALECT_OPENACC_OPENACC_H_
+#include "mlir/Dialect/OpenACC/OpenACCVariableInfo.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 25e3dbd29043d..513e9c6d1dab1 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -1444,11 +1444,13 @@ def OpenACC_PrivateRecipeOp
/// and it must be a valid place for this operation to be inserted. The
/// `recipeName` must be a unique name to prevent "redefinition of symbol"
/// IR errors.
+ /// The `hostVar` is the original host variable from which the type and
+ /// language-specific metadata are derived.
static std::optional<PrivateRecipeOp> createAndPopulate(
::mlir::OpBuilder &builder,
::mlir::Location loc,
::llvm::StringRef recipeName,
- ::mlir::Type varType,
+ ::mlir::Value hostVar,
::llvm::StringRef varName = "",
::mlir::ValueRange bounds = {});
@@ -1569,11 +1571,13 @@ def OpenACC_FirstprivateRecipeOp
/// and it must be a valid place for this operation to be inserted. The
/// `recipeName` must be a unique name to prevent "redefinition of symbol"
/// IR errors.
+ /// The `hostVar` is the original host variable from which the type and
+ /// language-specific metadata are derived.
static std::optional<FirstprivateRecipeOp> createAndPopulate(
::mlir::OpBuilder &builder,
::mlir::Location loc,
::llvm::StringRef recipeName,
- ::mlir::Type varType,
+ ::mlir::Value hostVar,
::llvm::StringRef varName = "",
::mlir::ValueRange bounds = {});
}];
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
index 97def012990c0..9ba5c4d1ad250 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
@@ -354,6 +354,26 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
return ::mlir::acc::VariableTypeCategory::uncategorized;
}]
>,
+ InterfaceMethod<
+ /*description=*/[{
+ Produces a `VariableInfo` for a host variable. This enables passing
+ language-specific metadata (that is not captured in the type system)
+ to recipe code-generation helpers such as `generatePrivateInit`,
+ `generateCopy`, and `generatePrivateDestroy`.
+
+ The `var` is the host variable from which to extract information.
+ Implementations may use `getDefiningOp()` on this value.
+
+ The default implementation returns a null `VariableInfo`.
+ }],
+ /*retTy=*/"::mlir::acc::VariableInfo",
+ /*methodName=*/"genPrivateVariableInfo",
+ /*args=*/(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var),
+ /*methodBody=*/"",
+ /*defaultImplementation=*/[{
+ return ::mlir::acc::VariableInfo();
+ }]
+ >,
InterfaceMethod<
/*description=*/[{
Generates the operations that would be normally placed in a recipe's
@@ -368,6 +388,10 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
The `initVal` can be empty - it is primarily needed for reductions
to ensure the variable is also initialized with appropriate value.
+ The `varInfo` carries language-specific metadata about the original
+ host variable (produced by `genPrivateVariableInfo`). Implementations
+ can `dyn_cast` to their language-specific subclass.
+
The `needsDestroy` out-parameter is set by implementations to indicate
that destruction code must be generated after the returned private
variable usages, typically in the destroy region of recipe operations
@@ -387,6 +411,7 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
"::llvm::StringRef":$varName,
"::mlir::ValueRange":$extents,
"::mlir::Value":$initVal,
+ "const ::mlir::acc::VariableInfo &":$varInfo,
"bool &":$needsDestroy),
/*methodBody=*/"",
/*defaultImplementation=*/[{
@@ -395,6 +420,12 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
>,
InterfaceMethod<
/*description=*/[{
+ Generates copy operations from one mappable variable to another.
+ Typically used to implement firstprivate initialization.
+
+ The `varInfo` carries language-specific metadata about the original
+ host variable (produced by `genPrivateVariableInfo`). Implementations
+ can `dyn_cast` to their language-specific subclass.
}],
/*retTy=*/"bool",
/*methodName=*/"generateCopy",
@@ -402,7 +433,8 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
"::mlir::Location":$loc,
"::mlir::TypedValue<::mlir::acc::MappableType>":$from,
"::mlir::TypedValue<::mlir::acc::MappableType>":$to,
- "::mlir::ValueRange":$bounds),
+ "::mlir::ValueRange":$bounds,
+ "const ::mlir::acc::VariableInfo &":$varInfo),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return false;
@@ -438,7 +470,11 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
this function should be a no-op and return `true`.
The `bounds` must be passed when only a section of the variable was
- privatized.
+ privatized.
+
+ The `varInfo` carries language-specific metadata about the original
+ host variable (produced by `genPrivateVariableInfo`). Implementations
+ can `dyn_cast` to their language-specific subclass.
Returns true if destruction was successfully generated or deemed not
necessary, false otherwise.
@@ -448,7 +484,8 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
/*args=*/(ins "::mlir::OpBuilder &":$builder,
"::mlir::Location":$loc,
"::mlir::Value":$privatized,
- "::mlir::ValueRange":$extents),
+ "::mlir::ValueRange":$extents,
+ "const ::mlir::acc::VariableInfo &":$varInfo),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return true;
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h
new file mode 100644
index 0000000000000..75bd92a4935ce
--- /dev/null
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h
@@ -0,0 +1,78 @@
+//===- OpenACCVariableInfo.h - OpenACC Variable Info -------------*- 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 VariableInfo classes used to carry language-specific
+// variable metadata through the OpenACC type interfaces. The OpenACC dialect
+// type interface methods (e.g., generatePrivateInit, generateCopy,
+// generatePrivateDestroy) receive a VariableInfo that language implementations
+// can dyn_cast to their own subclass to recover information not available from
+// the type system alone (e.g., whether a Fortran variable is OPTIONAL).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H
+#define MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H
+
+#include <memory>
+
+namespace mlir::acc {
+
+/// Base class for language-specific variable information.
+///
+/// Languages should derive from this class and use LLVM-style RTTI
+/// (via a `classof` static method and the `getLanguage()` discriminator) so
+/// that consumers can dyn_cast to the concrete type.
+///
+/// See llvm/docs/HowToSetUpLLVMStyleRTTI.rst for details on the pattern.
+class VariableInfoBase {
+public:
+ enum Language { Fortran, C, CPP };
+
+ Language getLanguage() const { return lang; }
+ virtual ~VariableInfoBase() = default;
+
+protected:
+ explicit VariableInfoBase(Language lang) : lang(lang) {}
+
+private:
+ Language lang;
+};
+
+/// A type-erased, move-only wrapper for language-specific variable
+/// information. This is modeled after the PointerUnion discrimination pattern:
+/// language implementations can use `dyn_cast<ConcreteType>()` to recover
+/// their specific metadata.
+///
+/// A default-constructed VariableInfo is null and carries no information.
+class VariableInfo {
+public:
+ VariableInfo() = default;
+ VariableInfo(std::nullptr_t) {}
+ explicit VariableInfo(std::unique_ptr<VariableInfoBase> impl)
+ : impl(std::move(impl)) {}
+
+ VariableInfo(VariableInfo &&) = default;
+ VariableInfo &operator=(VariableInfo &&) = default;
+
+ template <typename T>
+ const T *dyn_cast() const {
+ if (!impl || !T::classof(impl.get()))
+ return nullptr;
+ return static_cast<const T *>(impl.get());
+ }
+
+ explicit operator bool() const { return impl != nullptr; }
+
+private:
+ std::unique_ptr<VariableInfoBase> impl;
+};
+
+} // namespace mlir::acc
+
+#endif // MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index 800305ffb36c5..c8545a8373a97 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -1543,10 +1543,16 @@ struct RemoveConstantIfConditionWithRegion : public OpRewritePattern<OpTy> {
/// Create and populate an init region for privatization recipes.
/// Returns success if the region is populated, failure otherwise.
/// Sets needsFree to indicate if the allocated memory requires deallocation.
+/// The `hostVar` is the original host variable used to derive
+/// language-specific metadata via `genPrivateVariableInfo`.
+/// The `varInfo` output parameter is set to the variable info produced.
static LogicalResult createInitRegion(OpBuilder &builder, Location loc,
- Region &initRegion, Type varType,
+ Region &initRegion, Value hostVar,
StringRef varName, ValueRange bounds,
- bool &needsFree) {
+ bool &needsFree,
+ acc::VariableInfo &varInfo) {
+ Type varType = hostVar.getType();
+
// Create init block with arguments: original value + bounds
SmallVector<Type> argTypes{varType};
SmallVector<Location> argLocs{loc};
@@ -1568,8 +1574,10 @@ static LogicalResult createInitRegion(OpBuilder &builder, Location loc,
if (isa<MappableType>(varType)) {
auto mappableTy = cast<MappableType>(varType);
auto typedVar = cast<TypedValue<MappableType>>(blockArgVar);
+ auto typedHostVar = cast<TypedValue<MappableType>>(hostVar);
+ varInfo = mappableTy.genPrivateVariableInfo(typedHostVar);
privatizedValue = mappableTy.generatePrivateInit(
- builder, loc, typedVar, varName, bounds, {}, needsFree);
+ builder, loc, typedVar, varName, bounds, {}, varInfo, needsFree);
if (!privatizedValue)
return failure();
} else {
@@ -1635,9 +1643,12 @@ static LogicalResult createCopyRegion(OpBuilder &builder, Location loc,
/// Create and populate a destroy region for privatization recipes.
/// Returns success if the region is populated, failure otherwise.
+/// The `varInfo` carries language-specific metadata produced by
+/// `createInitRegion`.
static LogicalResult createDestroyRegion(OpBuilder &builder, Location loc,
Region &destroyRegion, Type varType,
- Value allocRes, ValueRange bounds) {
+ Value allocRes, ValueRange bounds,
+ const acc::VariableInfo &varInfo) {
// Create destroy block with arguments: original value + privatized value +
// bounds
SmallVector<Type> destroyArgTypes{varType, varType};
@@ -1655,7 +1666,8 @@ static LogicalResult createDestroyRegion(OpBuilder &builder, Location loc,
cast<TypedValue<PointerLikeType>>(destroyBlock->getArgument(1));
if (isa<MappableType>(varType)) {
auto mappableTy = cast<MappableType>(varType);
- if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds))
+ if (!mappableTy.generatePrivateDestroy(builder, loc, varToFree, bounds,
+ varInfo))
return failure();
} else {
assert(isa<PointerLikeType>(varType) && "Expected PointerLikeType");
@@ -1717,8 +1729,10 @@ LogicalResult acc::PrivateRecipeOp::verifyRegions() {
std::optional<PrivateRecipeOp>
PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
- StringRef recipeName, Type varType,
+ StringRef recipeName, Value hostVar,
StringRef varName, ValueRange bounds) {
+ Type varType = hostVar.getType();
+
// First, validate that we can handle this variable type
bool isMappable = isa<MappableType>(varType);
bool isPointerLike = isa<PointerLikeType>(varType);
@@ -1734,8 +1748,9 @@ PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
// Populate the init region
bool needsFree = false;
- if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), varType,
- varName, bounds, needsFree))) {
+ acc::VariableInfo varInfo;
+ if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
+ varName, bounds, needsFree, varInfo))) {
recipe.erase();
return std::nullopt;
}
@@ -1748,7 +1763,7 @@ PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
Value allocRes = yieldOp.getOperand(0);
if (failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
- varType, allocRes, bounds))) {
+ varType, allocRes, bounds, varInfo))) {
recipe.erase();
return std::nullopt;
}
@@ -1811,8 +1826,10 @@ LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
std::optional<FirstprivateRecipeOp>
FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
- StringRef recipeName, Type varType,
+ StringRef recipeName, Value hostVar,
StringRef varName, ValueRange bounds) {
+ Type varType = hostVar.getType();
+
// First, validate that we can handle this variable type
bool isMappable = isa<MappableType>(varType);
bool isPointerLike = isa<PointerLikeType>(varType);
@@ -1828,8 +1845,9 @@ FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
// Populate the init region
bool needsFree = false;
- if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), varType,
- varName, bounds, needsFree))) {
+ acc::VariableInfo varInfo;
+ if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
+ varName, bounds, needsFree, varInfo))) {
recipe.erase();
return std::nullopt;
}
@@ -1849,7 +1867,7 @@ FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
Value allocRes = yieldOp.getOperand(0);
if (failed(createDestroyRegion(builder, loc, recipe.getDestroyRegion(),
- varType, allocRes, bounds))) {
+ varType, allocRes, bounds, varInfo))) {
recipe.erase();
return std::nullopt;
}
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
index 3b83a25429234..95c8d1076ccb0 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
@@ -365,7 +365,7 @@ ACCImplicitData::generatePrivateRecipe(ModuleOp &module, Value var,
builder.setInsertionPointToStart(module.getBody());
auto recipe =
- acc::PrivateRecipeOp::createAndPopulate(builder, loc, recipeName, type);
+ acc::PrivateRecipeOp::createAndPopulate(builder, loc, recipeName, var);
if (!recipe.has_value())
return accSupport.emitNYI(loc, "implicit private"), nullptr;
return recipe.value();
@@ -390,7 +390,7 @@ ACCImplicitData::generateFirstprivateRecipe(ModuleOp &module, Value var,
builder.setInsertionPointToStart(module.getBody());
auto recipe = acc::FirstprivateRecipeOp::createAndPopulate(builder, loc,
- recipeName, type);
+ recipeName, var);
if (!recipe.has_value())
return accSupport.emitNYI(loc, "implicit firstprivate"), nullptr;
return recipe.value();
diff --git a/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp b/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
index 2506ca4fc39ce..7b71f2c5f3b20 100644
--- a/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
+++ b/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
@@ -80,15 +80,15 @@ void TestRecipePopulatePass::runOnOperation() {
ValueRange bounds; // No bounds for memref tests
if (recipeType == "private") {
- auto recipe = PrivateRecipeOp::createAndPopulate(
- builder, loc, recipeName, var.getType(), varName, bounds);
+ auto recipe = PrivateRecipeOp::createAndPopulate(builder, loc, recipeName,
+ var, varName, bounds);
if (!recipe) {
op->emitError("Failed to create private recipe for ") << varName;
}
} else if (recipeType == "firstprivate") {
auto recipe = FirstprivateRecipeOp::createAndPopulate(
- builder, loc, recipeName, var.getType(), varName, bounds);
+ builder, loc, recipeName, var, varName, bounds);
if (!recipe) {
op->emitError("Failed to create firstprivate recipe for ") << varName;
@@ -101,7 +101,7 @@ void TestRecipePopulatePass::runOnOperation() {
std::string privName = "private_from_firstprivate_" + varName;
auto firstpriv = FirstprivateRecipeOp::createAndPopulate(
- builder, loc, firstprivName, var.getType(), varName, bounds);
+ builder, loc, firstprivName, var, varName, bounds);
if (!firstpriv) {
op->emitError("Failed to create firstprivate recipe for ") << varName;
>From cbbc83c135a0a1a9582bc76454b1d902937c1307 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Fri, 13 Mar 2026 12:24:38 -0700
Subject: [PATCH 2/3] use Attribute instead of custom class
---
.../include/flang/Optimizer/Dialect/FIRAttr.h | 1 +
.../flang/Optimizer/Dialect/FIRAttr.td | 13 +++
.../Support/FIROpenACCTypeInterfaces.h | 8 +-
.../OpenACC/Support/FortranVariableInfo.h | 41 ----------
.../Support/FIROpenACCTypeInterfaces.cpp | 45 +++++------
.../OpenACC/Support/FIROpenACCUtils.cpp | 5 +-
.../mlir/Dialect/OpenACC/OpenACCAttributes.td | 24 ++++++
.../mlir/Dialect/OpenACC/OpenACCOps.td | 1 +
.../Dialect/OpenACC/OpenACCTypeInterfaces.td | 10 +--
.../Dialect/OpenACC/OpenACCVariableInfo.h | 80 ++++++-------------
mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp | 8 +-
11 files changed, 101 insertions(+), 135 deletions(-)
delete mode 100644 flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h
create mode 100644 mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.h b/flang/include/flang/Optimizer/Dialect/FIRAttr.h
index 06ec1f57173c3..ec6b7ff48329e 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.h
@@ -13,6 +13,7 @@
#ifndef FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H
#define FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H
+#include "mlir/Dialect/OpenACC/OpenACCVariableInfo.h"
#include "mlir/IR/BuiltinAttributes.h"
namespace mlir {
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index b23d28fdde55c..3bb1f443f3a5d 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -14,6 +14,7 @@
#define FIR_DIALECT_FIR_ATTRS
include "flang/Optimizer/Dialect/FIRDialect.td"
+include "mlir/Dialect/OpenACC/OpenACCAttributes.td"
include "mlir/IR/EnumAttr.td"
class fir_Attr<string name> : AttrDef<FIROpsDialect, name>;
@@ -262,4 +263,16 @@ def fir_UseRenameAttr : fir_Attr<"UseRename"> {
let assemblyFormat = "`<` $local_name `,` $symbol `>`";
}
+// Fortran-specific variable information for OpenACC.
+// Carries metadata that cannot be recovered from the FIR type system alone
+// and is required in the FIR implementation of OpenACC type interfaces.
+def fir_OpenACCFortranVariableInfoAttr
+ : AttrDef<FIROpsDialect, "OpenACCFortranVariableInfo",
+ [OpenACC_IsVariableInfoAttr],
+ "::mlir::acc::VariableInfoAttr"> {
+ let mnemonic = "acc_var_info";
+ let parameters = (ins "bool":$mayBeOptional);
+ let assemblyFormat = "`<` struct(params) `>`";
+}
+
#endif // FIR_DIALECT_FIR_ATTRS
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
index a31d3d9798ff8..01a1e19afd74b 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
@@ -80,7 +80,7 @@ struct OpenACCMappableModel
mlir::acc::VariableTypeCategory getTypeCategory(mlir::Type type,
mlir::Value var) const;
- mlir::acc::VariableInfo
+ mlir::acc::VariableInfoAttr
genPrivateVariableInfo(mlir::Type type,
mlir::TypedValue<mlir::acc::MappableType> var) const;
@@ -89,20 +89,20 @@ struct OpenACCMappableModel
mlir::TypedValue<mlir::acc::MappableType> var,
llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- const mlir::acc::VariableInfo &varInfo,
+ mlir::acc::VariableInfoAttr varInfo,
bool &needsDestroy) const;
bool generatePrivateDestroy(mlir::Type type, mlir::OpBuilder &builder,
mlir::Location loc, mlir::Value privatized,
mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const;
+ mlir::acc::VariableInfoAttr varInfo) const;
bool generateCopy(mlir::Type type, mlir::OpBuilder &mlirBuilder,
mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> source,
mlir::TypedValue<mlir::acc::MappableType> dest,
mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const;
+ mlir::acc::VariableInfoAttr varInfo) const;
bool generateCombiner(mlir::Type type, mlir::OpBuilder &mlirBuilder,
mlir::Location loc,
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h b/flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h
deleted file mode 100644
index 0b5a9518bd00b..0000000000000
--- a/flang/include/flang/Optimizer/OpenACC/Support/FortranVariableInfo.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- FortranVariableInfo.h - Fortran variable info for OpenACC -*- 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
-//
-//===----------------------------------------------------------------------===//
-//
-// Fortran-specific variable information carried through the OpenACC type
-// interface helpers (generatePrivateInit, generateCopy,
-// generatePrivateDestroy). This allows recovering properties such as
-// OPTIONAL that are not representable in the FIR type system.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FLANG_OPTIMIZER_OPENACC_FORTRANVARIABLEINFO_H
-#define FLANG_OPTIMIZER_OPENACC_FORTRANVARIABLEINFO_H
-
-#include "mlir/Dialect/OpenACC/OpenACCVariableInfo.h"
-
-namespace fir::acc {
-
-class FortranVariableInfo : public mlir::acc::VariableInfoBase {
-public:
- explicit FortranVariableInfo(bool mayBeOptional)
- : VariableInfoBase(Language::Fortran), mayBeOptional_(mayBeOptional) {}
-
- bool getMayBeOptional() const { return mayBeOptional_; }
-
- static bool classof(const VariableInfoBase *base) {
- return base->getLanguage() == Language::Fortran;
- }
-
-private:
- bool mayBeOptional_;
-};
-
-} // namespace fir::acc
-
-#endif // FLANG_OPTIMIZER_OPENACC_FORTRANVARIABLEINFO_H
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index 697ec33c167b8..5526dad0bffce 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -24,7 +24,6 @@
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
-#include "flang/Optimizer/OpenACC/Support/FortranVariableInfo.h"
#include "flang/Optimizer/Support/Utils.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
@@ -544,26 +543,26 @@ OpenACCMappableModel<fir::PointerType>::getTypeCategory(mlir::Type type,
mlir::Value var) const;
template <typename Ty>
-mlir::acc::VariableInfo OpenACCMappableModel<Ty>::genPrivateVariableInfo(
+mlir::acc::VariableInfoAttr OpenACCMappableModel<Ty>::genPrivateVariableInfo(
mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const {
hlfir::Entity entity{var};
- return mlir::acc::VariableInfo(
- std::make_unique<FortranVariableInfo>(entity.mayBeOptional()));
+ return fir::OpenACCFortranVariableInfoAttr::get(var.getContext(),
+ entity.mayBeOptional());
}
-template mlir::acc::VariableInfo
+template mlir::acc::VariableInfoAttr
OpenACCMappableModel<fir::BaseBoxType>::genPrivateVariableInfo(
mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
-template mlir::acc::VariableInfo
+template mlir::acc::VariableInfoAttr
OpenACCMappableModel<fir::ReferenceType>::genPrivateVariableInfo(
mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
-template mlir::acc::VariableInfo
+template mlir::acc::VariableInfoAttr
OpenACCMappableModel<fir::HeapType>::genPrivateVariableInfo(
mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
-template mlir::acc::VariableInfo
+template mlir::acc::VariableInfoAttr
OpenACCMappableModel<fir::PointerType>::genPrivateVariableInfo(
mlir::Type type, mlir::TypedValue<mlir::acc::MappableType> var) const;
@@ -743,7 +742,7 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange bounds, mlir::Value initVal,
- const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const {
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const {
mlir::ModuleOp mod = mlirBuilder.getInsertionBlock()
->getParent()
->getParentOfType<mlir::ModuleOp>();
@@ -927,34 +926,34 @@ OpenACCMappableModel<fir::BaseBoxType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
template mlir::Value
OpenACCMappableModel<fir::ReferenceType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
template mlir::Value OpenACCMappableModel<fir::HeapType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
template mlir::Value
OpenACCMappableModel<fir::PointerType>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
mlir::ValueRange extents, mlir::Value initVal,
- const mlir::acc::VariableInfo &varInfo, bool &needsDestroy) const;
+ mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const;
template <typename Ty>
bool OpenACCMappableModel<Ty>::generateCopy(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> src,
mlir::TypedValue<mlir::acc::MappableType> dest, mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const {
+ mlir::acc::VariableInfoAttr varInfo) const {
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
assert(mod && "failed to retrieve parent module");
@@ -992,22 +991,22 @@ template bool OpenACCMappableModel<fir::BaseBoxType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
- const mlir::acc::VariableInfo &) const;
+ mlir::acc::VariableInfoAttr) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
- const mlir::acc::VariableInfo &) const;
+ mlir::acc::VariableInfoAttr) const;
template bool OpenACCMappableModel<fir::PointerType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
- const mlir::acc::VariableInfo &) const;
+ mlir::acc::VariableInfoAttr) const;
template bool OpenACCMappableModel<fir::HeapType>::generateCopy(
mlir::Type, mlir::OpBuilder &, mlir::Location,
mlir::TypedValue<mlir::acc::MappableType>,
mlir::TypedValue<mlir::acc::MappableType>, mlir::ValueRange,
- const mlir::acc::VariableInfo &) const;
+ mlir::acc::VariableInfoAttr) const;
template <typename Op>
static mlir::Value genLogicalCombiner(fir::FirOpBuilder &builder,
@@ -1210,7 +1209,7 @@ template <typename Ty>
bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::Value privatized, mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const {
+ mlir::acc::VariableInfoAttr varInfo) const {
hlfir::Entity inputVar = hlfir::Entity{privatized};
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
@@ -1246,19 +1245,19 @@ bool OpenACCMappableModel<Ty>::generatePrivateDestroy(
template bool OpenACCMappableModel<fir::BaseBoxType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized, mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const;
+ mlir::acc::VariableInfoAttr varInfo) const;
template bool OpenACCMappableModel<fir::ReferenceType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized, mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const;
+ mlir::acc::VariableInfoAttr varInfo) const;
template bool OpenACCMappableModel<fir::HeapType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized, mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const;
+ mlir::acc::VariableInfoAttr varInfo) const;
template bool OpenACCMappableModel<fir::PointerType>::generatePrivateDestroy(
mlir::Type type, mlir::OpBuilder &builder, mlir::Location loc,
mlir::Value privatized, mlir::ValueRange bounds,
- const mlir::acc::VariableInfo &varInfo) const;
+ mlir::acc::VariableInfoAttr varInfo) const;
template <typename Ty>
mlir::Value OpenACCPointerLikeModel<Ty>::genAllocate(
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index e331d968301fb..68bebc00cbd5f 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -493,7 +493,8 @@ static RecipeOp genRecipeOp(
assert(mappableTy &&
"Expected that all variable types are considered mappable");
auto initArg = mlir::cast<MappableValue>(initBlock->getArgument(0));
- mlir::acc::VariableInfo varInfo = mappableTy.genPrivateVariableInfo(initArg);
+ mlir::acc::VariableInfoAttr varInfo =
+ mappableTy.genPrivateVariableInfo(initArg);
bool needsDestroy = false;
llvm::SmallVector<mlir::Value> initBounds =
getRecipeBounds(builder, loc, dataOperationBounds,
@@ -578,7 +579,7 @@ mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe(
auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
assert(mappableTy &&
"Expected that all variable types are considered mappable");
- mlir::acc::VariableInfo copyVarInfo =
+ mlir::acc::VariableInfoAttr copyVarInfo =
mappableTy.genPrivateVariableInfo(source);
[[maybe_unused]] bool success = mappableTy.generateCopy(
builder, loc, source, destination, copyBounds, copyVarInfo);
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td
new file mode 100644
index 0000000000000..4c2efba461184
--- /dev/null
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td
@@ -0,0 +1,24 @@
+//===- OpenACCAttributes.td - OpenACC Attributes -----------*- tablegen -*-===//
+//
+// Part of the MLIR 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines OpenACC Attributes than can be extended by the dialects outside of
+// of OpenACC.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENACC_ATTRIBUTES
+#define OPENACC_ATTRIBUTES
+
+include "mlir/IR/AttrTypeBase.td"
+
+// Trait for attributes that carry OpenACC variable information.
+def OpenACC_IsVariableInfoAttr : NativeAttrTrait<"IsVariableInfo"> {
+ let cppNamespace = "::mlir::acc::AttributeTrait";
+}
+
+#endif // OPENACC_ATTRIBUTES
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 513e9c6d1dab1..0eec7fb352591 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -20,6 +20,7 @@ include "mlir/IR/BuiltinTypes.td"
include "mlir/IR/EnumAttr.td"
include "mlir/IR/OpBase.td"
include "mlir/IR/SymbolInterfaces.td"
+include "mlir/Dialect/OpenACC/OpenACCAttributes.td"
include "mlir/Dialect/OpenACC/OpenACCBase.td"
include "mlir/Dialect/OpenACC/OpenACCOpsTypes.td"
include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.td"
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
index 9ba5c4d1ad250..3bd4e5c679659 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
@@ -366,12 +366,12 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
The default implementation returns a null `VariableInfo`.
}],
- /*retTy=*/"::mlir::acc::VariableInfo",
+ /*retTy=*/"::mlir::acc::VariableInfoAttr",
/*methodName=*/"genPrivateVariableInfo",
/*args=*/(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var),
/*methodBody=*/"",
/*defaultImplementation=*/[{
- return ::mlir::acc::VariableInfo();
+ return ::mlir::acc::VariableInfoAttr();
}]
>,
InterfaceMethod<
@@ -411,7 +411,7 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
"::llvm::StringRef":$varName,
"::mlir::ValueRange":$extents,
"::mlir::Value":$initVal,
- "const ::mlir::acc::VariableInfo &":$varInfo,
+ "::mlir::acc::VariableInfoAttr":$varInfo,
"bool &":$needsDestroy),
/*methodBody=*/"",
/*defaultImplementation=*/[{
@@ -434,7 +434,7 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
"::mlir::TypedValue<::mlir::acc::MappableType>":$from,
"::mlir::TypedValue<::mlir::acc::MappableType>":$to,
"::mlir::ValueRange":$bounds,
- "const ::mlir::acc::VariableInfo &":$varInfo),
+ "::mlir::acc::VariableInfoAttr":$varInfo),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return false;
@@ -485,7 +485,7 @@ def OpenACC_MappableTypeInterface : TypeInterface<"MappableType"> {
"::mlir::Location":$loc,
"::mlir::Value":$privatized,
"::mlir::ValueRange":$extents,
- "const ::mlir::acc::VariableInfo &":$varInfo),
+ "::mlir::acc::VariableInfoAttr":$varInfo),
/*methodBody=*/"",
/*defaultImplementation=*/[{
return true;
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h
index 75bd92a4935ce..95009fdb53fb4 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCVariableInfo.h
@@ -1,5 +1,4 @@
-//===- OpenACCVariableInfo.h - OpenACC Variable Info -------------*- C++
-//-*-===//
+//===- OpenACCVariableInfo.h - OpenACC Variable Info Attr -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,72 +6,41 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the VariableInfo classes used to carry language-specific
-// variable metadata through the OpenACC type interfaces. The OpenACC dialect
-// type interface methods (e.g., generatePrivateInit, generateCopy,
-// generatePrivateDestroy) receive a VariableInfo that language implementations
-// can dyn_cast to their own subclass to recover information not available from
-// the type system alone (e.g., whether a Fortran variable is OPTIONAL).
+// This file defines the VariableInfoAttr base class and the IsVariableInfo
+// trait.
+//
+// Any dialect can define Language-specific variable metadata attribute by
+// manually attaching the IsVariableInfo trait and using VariableInfoAttr as
+// the baseCppClass.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H
#define MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H
-#include <memory>
-
-namespace mlir::acc {
-
-/// Base class for language-specific variable information.
-///
-/// Languages should derive from this class and use LLVM-style RTTI
-/// (via a `classof` static method and the `getLanguage()` discriminator) so
-/// that consumers can dyn_cast to the concrete type.
-///
-/// See llvm/docs/HowToSetUpLLVMStyleRTTI.rst for details on the pattern.
-class VariableInfoBase {
-public:
- enum Language { Fortran, C, CPP };
-
- Language getLanguage() const { return lang; }
- virtual ~VariableInfoBase() = default;
+#include "mlir/IR/Attributes.h"
-protected:
- explicit VariableInfoBase(Language lang) : lang(lang) {}
+namespace mlir {
+namespace acc {
+namespace AttributeTrait {
+/// Trait attached to attributes that are OpenACC variable info attributes.
+template <typename ConcreteType>
+struct IsVariableInfo
+ : public mlir::AttributeTrait::TraitBase<ConcreteType, IsVariableInfo> {};
+} // namespace AttributeTrait
-private:
- Language lang;
-};
-
-/// A type-erased, move-only wrapper for language-specific variable
-/// information. This is modeled after the PointerUnion discrimination pattern:
-/// language implementations can use `dyn_cast<ConcreteType>()` to recover
-/// their specific metadata.
-///
-/// A default-constructed VariableInfo is null and carries no information.
-class VariableInfo {
+/// Base attribute class for language-specific variable information carried
+/// through the OpenACC type interface helpers.
+class VariableInfoAttr : public mlir::Attribute {
public:
- VariableInfo() = default;
- VariableInfo(std::nullptr_t) {}
- explicit VariableInfo(std::unique_ptr<VariableInfoBase> impl)
- : impl(std::move(impl)) {}
-
- VariableInfo(VariableInfo &&) = default;
- VariableInfo &operator=(VariableInfo &&) = default;
+ using Attribute::Attribute;
- template <typename T>
- const T *dyn_cast() const {
- if (!impl || !T::classof(impl.get()))
- return nullptr;
- return static_cast<const T *>(impl.get());
+ static bool classof(mlir::Attribute attr) {
+ return attr.hasTrait<::mlir::acc::AttributeTrait::IsVariableInfo>();
}
-
- explicit operator bool() const { return impl != nullptr; }
-
-private:
- std::unique_ptr<VariableInfoBase> impl;
};
-} // namespace mlir::acc
+} // namespace acc
+} // namespace mlir
#endif // MLIR_DIALECT_OPENACC_OPENACCVARIABLEINFO_H
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index c8545a8373a97..2f56595016a57 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -1550,7 +1550,7 @@ static LogicalResult createInitRegion(OpBuilder &builder, Location loc,
Region &initRegion, Value hostVar,
StringRef varName, ValueRange bounds,
bool &needsFree,
- acc::VariableInfo &varInfo) {
+ acc::VariableInfoAttr &varInfo) {
Type varType = hostVar.getType();
// Create init block with arguments: original value + bounds
@@ -1648,7 +1648,7 @@ static LogicalResult createCopyRegion(OpBuilder &builder, Location loc,
static LogicalResult createDestroyRegion(OpBuilder &builder, Location loc,
Region &destroyRegion, Type varType,
Value allocRes, ValueRange bounds,
- const acc::VariableInfo &varInfo) {
+ acc::VariableInfoAttr varInfo) {
// Create destroy block with arguments: original value + privatized value +
// bounds
SmallVector<Type> destroyArgTypes{varType, varType};
@@ -1748,7 +1748,7 @@ PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
// Populate the init region
bool needsFree = false;
- acc::VariableInfo varInfo;
+ acc::VariableInfoAttr varInfo;
if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
varName, bounds, needsFree, varInfo))) {
recipe.erase();
@@ -1845,7 +1845,7 @@ FirstprivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
// Populate the init region
bool needsFree = false;
- acc::VariableInfo varInfo;
+ acc::VariableInfoAttr varInfo;
if (failed(createInitRegion(builder, loc, recipe.getInitRegion(), hostVar,
varName, bounds, needsFree, varInfo))) {
recipe.erase();
>From fa02645a5d06ab57671b66f161fcf07c826f4355 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 24 Mar 2026 03:27:00 -0700
Subject: [PATCH 3/3] thread hostVar to genRecipeOp
---
flang/include/flang/Lower/OpenACC.h | 20 -----
.../OpenACC/Support/FIROpenACCUtils.h | 6 +-
flang/lib/Lower/OpenACC.cpp | 11 ++-
.../Support/FIROpenACCTypeInterfaces.cpp | 4 +-
.../OpenACC/Support/FIROpenACCUtils.cpp | 75 ++++++++++++-------
.../OpenACC/acc-firstprivate-optional.f90 | 13 ++++
.../mlir/Dialect/OpenACC/OpenACCAttributes.td | 2 +-
7 files changed, 74 insertions(+), 57 deletions(-)
create mode 100644 flang/test/Lower/OpenACC/acc-firstprivate-optional.f90
diff --git a/flang/include/flang/Lower/OpenACC.h b/flang/include/flang/Lower/OpenACC.h
index c2a950f36c5a7..9ec4aa9c012b3 100644
--- a/flang/include/flang/Lower/OpenACC.h
+++ b/flang/include/flang/Lower/OpenACC.h
@@ -86,26 +86,6 @@ void genOpenACCRoutineConstruct(
AbstractConverter &, mlir::ModuleOp, mlir::func::FuncOp,
const std::vector<Fortran::semantics::OpenACCRoutineInfo> &);
-/// Get a acc.private.recipe op for the given type or create it if it does not
-/// exist yet.
-mlir::acc::PrivateRecipeOp
-createOrGetPrivateRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location,
- mlir::Type,
- llvm::SmallVector<mlir::Value> &dataOperationBounds);
-
-/// Get a acc.reduction.recipe op for the given type or create it if it does not
-/// exist yet.
-mlir::acc::ReductionRecipeOp
-createOrGetReductionRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location,
- mlir::Type, mlir::acc::ReductionOperator,
- llvm::SmallVector<mlir::Value> &dataOperationBounds);
-
-/// Get a acc.firstprivate.recipe op for the given type or create it if it does
-/// not exist yet.
-mlir::acc::FirstprivateRecipeOp createOrGetFirstprivateRecipe(
- fir::FirOpBuilder &, llvm::StringRef, mlir::Location, mlir::Type,
- llvm::SmallVector<mlir::Value> &dataOperationBounds);
-
void attachDeclarePostAllocAction(AbstractConverter &, fir::FirOpBuilder &,
const Fortran::semantics::Symbol &);
void attachDeclarePreDeallocAction(AbstractConverter &, fir::FirOpBuilder &,
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
index 360f4eb000a9e..a8b9bcf5cfd4b 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h
@@ -60,7 +60,7 @@ bool areAllBoundsConstant(llvm::ArrayRef<mlir::Value> bounds);
/// \return The existing or created PrivateRecipeOp symbol
mlir::SymbolRefAttr
createOrGetPrivateRecipe(mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Type ty,
+ mlir::Value var,
llvm::SmallVector<mlir::Value> &dataBoundOps);
/// Create or get a firstprivate recipe for the given type and name.
@@ -71,7 +71,7 @@ createOrGetPrivateRecipe(mlir::OpBuilder &builder, mlir::Location loc,
/// \return The existing or created FirstprivateRecipeOp symbol
mlir::SymbolRefAttr
createOrGetFirstprivateRecipe(mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Type ty,
+ mlir::Value var,
llvm::SmallVector<mlir::Value> &dataBoundOps);
/// Create or get a reduction recipe for the given type, name and operator.
@@ -84,7 +84,7 @@ createOrGetFirstprivateRecipe(mlir::OpBuilder &builder, mlir::Location loc,
/// \return The existing or created ReductionRecipeOp symbol
mlir::SymbolRefAttr
createOrGetReductionRecipe(mlir::OpBuilder &builder, mlir::Location loc,
- mlir::Type ty, mlir::acc::ReductionOperator op,
+ mlir::Value var, mlir::acc::ReductionOperator op,
llvm::SmallVector<mlir::Value> &dataBoundOps,
mlir::Attribute fastMathAttr = {});
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 2136f1d540a6a..228a88b5bac0b 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -789,11 +789,11 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
// For private/firstprivate, attach (and optionally record) the recipe.
if constexpr (std::is_same_v<Op, mlir::acc::PrivateOp>) {
mlir::SymbolRefAttr recipeAttr = fir::acc::createOrGetPrivateRecipe(
- builder, operandLocation, baseAddr.getType(), bounds);
+ builder, operandLocation, baseAddr, bounds);
op.setRecipeAttr(recipeAttr);
} else if constexpr (std::is_same_v<Op, mlir::acc::FirstprivateOp>) {
mlir::SymbolRefAttr recipeAttr = fir::acc::createOrGetFirstprivateRecipe(
- builder, operandLocation, baseAddr.getType(), bounds);
+ builder, operandLocation, baseAddr, bounds);
op.setRecipeAttr(recipeAttr);
}
}
@@ -1176,13 +1176,12 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList,
/*structured=*/true, /*implicit=*/false,
mlir::acc::DataClause::acc_reduction, info.addr.getType(), async,
asyncDeviceTypes, asyncOnlyDeviceTypes, /*unwrapBoxAddr=*/true);
- mlir::Type ty = op.getAccVar().getType();
mlir::Attribute fastMathAttr;
if (builder.getFastMathFlags() != mlir::arith::FastMathFlags::none)
fastMathAttr = mlir::arith::FastMathFlagsAttr::get(
builder.getContext(), builder.getFastMathFlags());
mlir::SymbolRefAttr recipe = fir::acc::createOrGetReductionRecipe(
- builder, operandLocation, ty, mlirOp, bounds, fastMathAttr);
+ builder, operandLocation, info.addr, mlirOp, bounds, fastMathAttr);
op.setRecipeAttr(recipe);
reductionOperands.push_back(op.getAccVar());
// Track the symbol and its corresponding mlir::Value if requested so that
@@ -1427,8 +1426,8 @@ static void privatizeIv(
if (privateOp == nullptr) {
llvm::SmallVector<mlir::Value> noBounds;
- mlir::SymbolRefAttr recipe = fir::acc::createOrGetPrivateRecipe(
- builder, loc, ivValue.getType(), noBounds);
+ mlir::SymbolRefAttr recipe =
+ fir::acc::createOrGetPrivateRecipe(builder, loc, ivValue, noBounds);
std::stringstream asFortran;
asFortran << Fortran::lower::mangle::demangleName(toStringRef(sym.name()));
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index 5526dad0bffce..25af35513d18d 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -741,8 +741,8 @@ template <typename Ty>
mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
mlir::Type type, mlir::OpBuilder &mlirBuilder, mlir::Location loc,
mlir::TypedValue<mlir::acc::MappableType> var, llvm::StringRef varName,
- mlir::ValueRange bounds, mlir::Value initVal,
- mlir::acc::VariableInfoAttr varInfo, bool &needsDestroy) const {
+ mlir::ValueRange bounds, mlir::Value initVal, mlir::acc::VariableInfoAttr,
+ bool &needsDestroy) const {
mlir::ModuleOp mod = mlirBuilder.getInsertionBlock()
->getParent()
->getParentOfType<mlir::ModuleOp>();
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index 3f35d3a796d82..519978dba1afd 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -14,6 +14,7 @@
#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Builder/Complex.h"
#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
@@ -229,6 +230,7 @@ static std::string getBoundsString(llvm::ArrayRef<Value> bounds) {
}
static std::string getRecipeName(mlir::acc::RecipeKind kind, Type type,
+ mlir::acc::VariableInfoAttr varInfo,
const fir::KindMapping &kindMap,
llvm::ArrayRef<Value> bounds,
mlir::acc::ReductionOperator reductionOp =
@@ -256,19 +258,33 @@ static std::string getRecipeName(mlir::acc::RecipeKind kind, Type type,
break;
}
+ if (auto fortranVarInfo =
+ mlir::dyn_cast_if_present<fir::OpenACCFortranVariableInfoAttr>(
+ varInfo))
+ if (fortranVarInfo.getMayBeOptional())
+ prefixOS << "_optional";
+
if (!bounds.empty())
prefixOS << getBoundsString(bounds);
return fir::getTypeAsString(type, kindMap, prefixOS.str());
}
+using MappableValue = mlir::TypedValue<mlir::acc::MappableType>;
+
std::string fir::acc::getRecipeName(mlir::acc::RecipeKind kind, Type type,
Value var, llvm::ArrayRef<Value> bounds,
mlir::acc::ReductionOperator reductionOp) {
auto kindMap = var && var.getDefiningOp()
? fir::getKindMapping(var.getDefiningOp())
: fir::KindMapping(type.getContext());
- return ::getRecipeName(kind, type, kindMap, bounds, reductionOp);
+ mlir::acc::VariableInfoAttr varInfo;
+ if (var)
+ if (auto mappableTy =
+ mlir::dyn_cast<mlir::acc::MappableType>(var.getType()))
+ varInfo =
+ mappableTy.genPrivateVariableInfo(mlir::cast<MappableValue>(var));
+ return ::getRecipeName(kind, type, varInfo, kindMap, bounds, reductionOp);
}
/// Map acc::ReductionOperator to arith::AtomicRMWKind for identity value
@@ -397,8 +413,6 @@ static void addRecipeBoundsArgs(llvm::SmallVector<mlir::Value> &bounds,
}
}
-using MappableValue = mlir::TypedValue<mlir::acc::MappableType>;
-
// Generate the combiner or copy region block and block arguments and return the
// source and destination entities.
static std::pair<MappableValue, MappableValue>
@@ -420,7 +434,7 @@ genRecipeCombinerOrCopyRegion(fir::FirOpBuilder &builder, mlir::Location loc,
template <typename RecipeOp>
static RecipeOp genRecipeOp(
fir::FirOpBuilder &builder, mlir::ModuleOp mod, llvm::StringRef recipeName,
- mlir::Location loc, mlir::Type ty,
+ mlir::Location loc, mlir::Type ty, mlir::acc::VariableInfoAttr varInfo,
llvm::SmallVector<mlir::Value> &dataOperationBounds, bool allConstantBound,
mlir::acc::ReductionOperator op = mlir::acc::ReductionOperator::AccNone) {
mlir::OpBuilder modBuilder(mod.getBodyRegion());
@@ -460,8 +474,6 @@ static RecipeOp genRecipeOp(
assert(mappableTy &&
"Expected that all variable types are considered mappable");
auto initArg = mlir::cast<MappableValue>(initBlock->getArgument(0));
- mlir::acc::VariableInfoAttr varInfo =
- mappableTy.genPrivateVariableInfo(initArg);
bool needsDestroy = false;
llvm::SmallVector<mlir::Value> initBounds =
getRecipeBounds(builder, loc, dataOperationBounds,
@@ -503,31 +515,44 @@ static RecipeOp genRecipeOp(
mlir::SymbolRefAttr
fir::acc::createOrGetPrivateRecipe(mlir::OpBuilder &mlirBuilder,
- mlir::Location loc, mlir::Type ty,
+ mlir::Location loc, mlir::Value var,
llvm::SmallVector<mlir::Value> &bounds) {
+ mlir::Type ty = var.getType();
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
fir::FirOpBuilder builder(mlirBuilder, mod);
- std::string recipeName = ::getRecipeName(
- mlir::acc::RecipeKind::private_recipe, ty, builder.getKindMap(), bounds);
+ auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
+ assert(mappableTy &&
+ "Expected that all variable types are considered mappable");
+ mlir::acc::VariableInfoAttr varInfo =
+ mappableTy.genPrivateVariableInfo(mlir::cast<MappableValue>(var));
+ std::string recipeName =
+ ::getRecipeName(mlir::acc::RecipeKind::private_recipe, ty, varInfo,
+ builder.getKindMap(), bounds);
if (auto recipe = mod.lookupSymbol<mlir::acc::PrivateRecipeOp>(recipeName))
return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
mlir::OpBuilder::InsertionGuard guard(builder);
bool allConstantBound = fir::acc::areAllBoundsConstant(bounds);
auto recipe = genRecipeOp<mlir::acc::PrivateRecipeOp>(
- builder, mod, recipeName, loc, ty, bounds, allConstantBound);
+ builder, mod, recipeName, loc, ty, varInfo, bounds, allConstantBound);
return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
}
mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe(
- mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Type ty,
+ mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Value var,
llvm::SmallVector<mlir::Value> &dataBoundOps) {
+ mlir::Type ty = var.getType();
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
fir::FirOpBuilder builder(mlirBuilder, mod);
+ auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
+ assert(mappableTy &&
+ "Expected that all variable types are considered mappable");
+ mlir::acc::VariableInfoAttr varInfo =
+ mappableTy.genPrivateVariableInfo(mlir::cast<MappableValue>(var));
std::string recipeName =
- ::getRecipeName(mlir::acc::RecipeKind::firstprivate_recipe, ty,
+ ::getRecipeName(mlir::acc::RecipeKind::firstprivate_recipe, ty, varInfo,
builder.getKindMap(), dataBoundOps);
if (auto recipe =
mod.lookupSymbol<mlir::acc::FirstprivateRecipeOp>(recipeName))
@@ -536,35 +561,37 @@ mlir::SymbolRefAttr fir::acc::createOrGetFirstprivateRecipe(
mlir::OpBuilder::InsertionGuard guard(builder);
bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
auto recipe = genRecipeOp<mlir::acc::FirstprivateRecipeOp>(
- builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound);
+ builder, mod, recipeName, loc, ty, varInfo, dataBoundOps,
+ allConstantBound);
auto [source, destination] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCopyRegion(), dataBoundOps, allConstantBound);
llvm::SmallVector<mlir::Value> copyBounds =
getRecipeBounds(builder, loc, dataBoundOps,
recipe.getCopyRegion().getArguments().drop_front(2));
- auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
- assert(mappableTy &&
- "Expected that all variable types are considered mappable");
- mlir::acc::VariableInfoAttr copyVarInfo =
- mappableTy.genPrivateVariableInfo(source);
[[maybe_unused]] bool success = mappableTy.generateCopy(
- builder, loc, source, destination, copyBounds, copyVarInfo);
+ builder, loc, source, destination, copyBounds, varInfo);
assert(success && "failed to generate copy");
mlir::acc::TerminatorOp::create(builder, loc);
return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
}
mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe(
- mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Type ty,
+ mlir::OpBuilder &mlirBuilder, mlir::Location loc, mlir::Value var,
mlir::acc::ReductionOperator op,
llvm::SmallVector<mlir::Value> &dataBoundOps,
mlir::Attribute fastMathAttr) {
+ mlir::Type ty = var.getType();
mlir::ModuleOp mod =
mlirBuilder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>();
fir::FirOpBuilder builder(mlirBuilder, mod);
+ auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
+ assert(mappableTy &&
+ "Expected that all variable types are considered mappable");
+ mlir::acc::VariableInfoAttr varInfo =
+ mappableTy.genPrivateVariableInfo(mlir::cast<MappableValue>(var));
std::string recipeName =
- ::getRecipeName(mlir::acc::RecipeKind::reduction_recipe, ty,
+ ::getRecipeName(mlir::acc::RecipeKind::reduction_recipe, ty, varInfo,
builder.getKindMap(), dataBoundOps, op);
if (auto recipe = mod.lookupSymbol<mlir::acc::ReductionRecipeOp>(recipeName))
return mlir::SymbolRefAttr::get(builder.getContext(), recipe.getSymName());
@@ -572,7 +599,8 @@ mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe(
mlir::OpBuilder::InsertionGuard guard(builder);
bool allConstantBound = fir::acc::areAllBoundsConstant(dataBoundOps);
auto recipe = genRecipeOp<mlir::acc::ReductionRecipeOp>(
- builder, mod, recipeName, loc, ty, dataBoundOps, allConstantBound, op);
+ builder, mod, recipeName, loc, ty, varInfo, dataBoundOps,
+ allConstantBound, op);
auto [dest, source] = genRecipeCombinerOrCopyRegion(
builder, loc, ty, recipe.getCombinerRegion(), dataBoundOps,
@@ -581,9 +609,6 @@ mlir::SymbolRefAttr fir::acc::createOrGetReductionRecipe(
getRecipeBounds(builder, loc, dataBoundOps,
recipe.getCombinerRegion().getArguments().drop_front(2));
- auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(ty);
- assert(mappableTy &&
- "Expected that all variable types are considered mappable");
[[maybe_unused]] bool success = mappableTy.generateCombiner(
builder, loc, dest, source, combinerBounds, op, fastMathAttr);
assert(success && "failed to generate combiner");
diff --git a/flang/test/Lower/OpenACC/acc-firstprivate-optional.f90 b/flang/test/Lower/OpenACC/acc-firstprivate-optional.f90
new file mode 100644
index 0000000000000..876495bebaab8
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-firstprivate-optional.f90
@@ -0,0 +1,13 @@
+! Test handling of OPTIONAL in data directives
+! RUN: %flang_fc1 -fopenacc -emit-hlfir %s -o - | FileCheck %s
+
+subroutine test(x)
+ real, optional :: x(100)
+ !$acc parallel firstprivate(x)
+ call foo(x)
+ !$acc end parallel
+end subroutine
+
+! CHECK: acc.firstprivate.recipe @firstprivatization_optional_ref_100xf32
+
+! TODO: generate conditional copy
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td
index 4c2efba461184..f533fb42546fe 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCAttributes.td
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// Defines OpenACC Attributes than can be extended by the dialects outside of
+// Defines OpenACC Attributes that can be extended by the dialects outside of
// of OpenACC.
//
//===----------------------------------------------------------------------===//
More information about the flang-commits
mailing list