[flang-commits] [flang] [flang] Defined SafeTempArrayCopyAttrInterface for array repacking. (PR #134346)
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Thu Apr 3 22:22:15 PDT 2025
https://github.com/vzakhari created https://github.com/llvm/llvm-project/pull/134346
This patch defines `fir::SafeTempArrayCopyAttrInterface` and the corresponding
OpenACC/OpenMP related attributes in FIR dialect. The actual implementations
are just placeholders right now, and array repacking becomes a no-op
if `-fopenacc/-fopenmp` is used for the compilation.
>From 8696a47c5336815e1823bd8a351e8473b92b4673 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Thu, 3 Apr 2025 21:20:04 -0700
Subject: [PATCH 1/2] [flang] Defined SafeTempArrayCopyAttrInterface for array
repacking.
This patch defines `fir::SafeTempArrayCopyAttrInterface` and the corresponding
OpenACC/OpenMP related attributes in FIR dialect. The actual implementations
are just placeholders right now, and array repacking becomes a no-op
if `-fopenacc/-fopenmp` is used for the compilation.
---
flang/docs/ArrayRepacking.md | 10 +--
flang/include/flang/Lower/ConvertVariable.h | 4 +-
.../flang/Optimizer/Dialect/CMakeLists.txt | 5 ++
.../include/flang/Optimizer/Dialect/FIRAttr.h | 2 +
.../flang/Optimizer/Dialect/FIRAttr.td | 22 +++++
.../flang/Optimizer/Dialect/FIRDialect.h | 3 +
.../include/flang/Optimizer/Dialect/FIROps.h | 1 +
.../include/flang/Optimizer/Dialect/FIROps.td | 29 ++++++-
.../Dialect/SafeTempArrayCopyAttrInterface.h | 27 +++++++
.../Dialect/SafeTempArrayCopyAttrInterface.td | 81 +++++++++++++++++++
.../OpenACC/RegisterOpenACCExtensions.h | 8 ++
.../OpenMP/Support/RegisterOpenMPExtensions.h | 30 +++++++
.../include/flang/Optimizer/Support/InitFIR.h | 2 +
flang/lib/Frontend/CMakeLists.txt | 1 +
flang/lib/Frontend/FrontendActions.cpp | 1 +
flang/lib/Lower/ConvertVariable.cpp | 35 +++++---
flang/lib/Optimizer/CodeGen/CMakeLists.txt | 2 +
.../Optimizer/CodeGen/LowerRepackArrays.cpp | 43 +++++++++-
flang/lib/Optimizer/Dialect/CMakeLists.txt | 2 +
flang/lib/Optimizer/Dialect/FIRAttr.cpp | 10 +--
.../SafeTempArrayCopyAttrInterface.cpp | 15 ++++
flang/lib/Optimizer/OpenACC/CMakeLists.txt | 1 +
.../OpenACC/FIROpenACCAttributes.cpp | 67 +++++++++++++++
.../OpenACC/RegisterOpenACCExtensions.cpp | 1 +
flang/lib/Optimizer/OpenMP/CMakeLists.txt | 2 +
.../Optimizer/OpenMP/Support/CMakeLists.txt | 20 +++++
.../OpenMP/Support/FIROpenMPAttributes.cpp | 69 ++++++++++++++++
.../Support/RegisterOpenMPExtensions.cpp | 20 +++++
flang/test/Lower/repack-arrays-safe.f90 | 17 ++++
.../lower-repack-arrays-openacc.fir | 17 ++++
.../Transforms/lower-repack-arrays-openmp.fir | 17 ++++
flang/tools/bbc/CMakeLists.txt | 1 +
flang/tools/fir-lsp-server/CMakeLists.txt | 1 +
flang/tools/fir-opt/CMakeLists.txt | 1 +
flang/tools/tco/CMakeLists.txt | 1 +
35 files changed, 542 insertions(+), 26 deletions(-)
create mode 100644 flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h
create mode 100644 flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td
create mode 100644 flang/include/flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h
create mode 100644 flang/lib/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.cpp
create mode 100644 flang/lib/Optimizer/OpenACC/FIROpenACCAttributes.cpp
create mode 100644 flang/lib/Optimizer/OpenMP/Support/CMakeLists.txt
create mode 100644 flang/lib/Optimizer/OpenMP/Support/FIROpenMPAttributes.cpp
create mode 100644 flang/lib/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.cpp
create mode 100644 flang/test/Lower/repack-arrays-safe.f90
create mode 100644 flang/test/Transforms/lower-repack-arrays-openacc.fir
create mode 100644 flang/test/Transforms/lower-repack-arrays-openmp.fir
diff --git a/flang/docs/ArrayRepacking.md b/flang/docs/ArrayRepacking.md
index 7de599f293e40..69f955783f7ab 100755
--- a/flang/docs/ArrayRepacking.md
+++ b/flang/docs/ArrayRepacking.md
@@ -205,7 +205,7 @@ Arguments:
* `max-element-size` - constant integer attribute specifying the maximum byte element-size of an array that is eligible for repacking.
* `min-stride` - constant integer attribute specifying the minimum byte stride of the innermost dimension of an array that is eligible for repacking.
* `typeparams` - type parameters of the element type.
-* `*.temp_copy_is_safe`: a list of attributes implementing `TempCopyIsSafe` attribute interface for generating a boolean value indicating whether using a temporary copy instead of the original array is safe in the current context.
+* `is-safe`: a list of attributes implementing `fir::SafeTempArrayCopyAttrInterface` attribute interface for generating a boolean value indicating whether using a temporary copy instead of the original array is safe in the current context.
Memory effects are conservative, assuming that an allocation and copy may happen:
@@ -243,7 +243,7 @@ Memory effects are conservative, assuming that a copy and deallocation may happe
### New attribute interface
-The `TempCopyIsSafe` attribute interface provides means to generate programming model specific predicates saying whether repacking is safe or not at the point where it needs to be done. For example the OpenMP MLIR dialect may provide an attribute implementing this interface to generate a runtime check at the point of packing array `x` inside subroutine `repacking`. A conservative implementation might look like this:
+The `fir::SafeTempArrayCopyAttrInterface` attribute interface provides means to generate programming model specific predicates saying whether repacking is safe or not at the point where it needs to be done. For example the OpenMP MLIR dialect may provide an attribute implementing this interface to generate a runtime check at the point of packing array `x` inside subroutine `repacking`. A conservative implementation might look like this:
```C
repacking_is_safe = omp_get_num_team() == 1 && omp_get_num_threads() == 1;
@@ -297,7 +297,7 @@ end program main
So the most conservative implementation of the predicate generator may be to always produce `false` value. Flang lowering may attach any number of such attributes to `fir.pack_array` depending on the compilation context and options.
-[TBD] define `TempCopyIsSafe` attribute interface so that OpenACC/OpenMP dialects can provide their specific attributes, which can be used to generate static/runtime checks for safety of the temporary copy in particular context.
+`fir::SafeTempArrayCopyAttrInterface` is defined in `flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td`. The OpenACC-specific implementation is defined in `lib/Optimizer/OpenACC/FIROpenACCAttributes.cpp`. The OpenMP-specific implementation is defined in `lib/Optimizer/OpenMP/Support/FIROpenMPAttributes.cpp`
#### Alternatives/additions to the attribute interface
@@ -305,7 +305,7 @@ The following ideas were expressed during the review, and they are worth conside
| |
| - |
-| For OpenACC/OpenMP runtime to be able to detect/handle the presence of the original array and the temporary copy in the device data environment, descriptor flags/properties might be used to mark the copy's descriptor as such and provide a link to the original array (or its descriptor). It may be problematic to maintain such flags/properties, in general, because of the repacking that may happen, especially, in C code, where the flags/properties might be dropped. Moreover, a copy array might be repacked into another copy array multiple times, so a descriptor might need to keep a chain of associated arrays and it will have to be maintained as well.<br>An alternative to tracking the original-copy "association" might be compiler generated code notifying the OpenACC/OpenMP offload runtime about the copy being created/deleted for the original array, so that the offload runtime can disallow repacking or report an error when the repacking is definitely causing the program to behave incorrectly. The compiler may report the "association" to the runtime through callbacks provided by `TempCopyIsSafe` attribute interface, and this will require proper bookkeeping in the runtime specific to the array repacking. |
+| For OpenACC/OpenMP runtime to be able to detect/handle the presence of the original array and the temporary copy in the device data environment, descriptor flags/properties might be used to mark the copy's descriptor as such and provide a link to the original array (or its descriptor). It may be problematic to maintain such flags/properties, in general, because of the repacking that may happen, especially, in C code, where the flags/properties might be dropped. Moreover, a copy array might be repacked into another copy array multiple times, so a descriptor might need to keep a chain of associated arrays and it will have to be maintained as well.<br>An alternative to tracking the original-copy "association" might be compiler generated code notifying the OpenACC/OpenMP offload runtime about the copy being created/deleted for the original array, so that the offload runtime can disallow repacking or report an error when the repacking is definitely causing the program to behave incorrectly. The compiler may report the "association" to the runtime through callbacks provided by `fir::SafeTempArrayCopyAttrInterface` attribute interface, and this will require proper bookkeeping in the runtime specific to the array repacking. |
| There may be some uses for an API allowing to statically determine whether a given descriptor (SSA value) represent the repacked copy of the original array. For example, it may be in the form of an API in the OpenACC `MappableType` interface. This can be done with some limitations for the values produced by `fir.pack_array` that are dynamic (i.e. the copy is created conditionally based on the runtime checks). |
| The compiler can also try to statically determine the conditions where the array repacking might be unsafe, e.g. a presence of memory barriers or operations carrying implicit memory barriers, presence of atomic operations between the `pack/unpack` operations may indicate non-trivial handling of the array memory. Such checks may result in the removal of `pack/unpack` operations, and they can probably be done in a mandatory pass (not an optimization pass). At the same time, the result of the checks may depend on other optimization passes (e.g. inlining), so the behavior may be inconsistent between different optimization levels. |
@@ -373,7 +373,7 @@ Lowering of the new operations (after all the optimizations) might be done in a
`fir.pack_array` lowering might be done in the following steps:
* If there are dynamic constraints, generate a boolean `p1` that is set to true if repacking has to be done (depending on the constraints values and the original array descriptor). The IR might be cleaner if we generate a Fortran runtime call here.
-* If there are attributes implementing `TempCopyIsSafe` attribute interface, then use the interface method to generate boolean predicates for each such attribute: `p2`, ..., `pn`.
+* If there are attributes implementing `fir::SafeTempArrayCopyAttrInterface` attribute interface, then use the interface method to generate boolean predicates for each such attribute: `p2`, ..., `pn`.
* [TBD] it seems that the runtime checks for the target offload programs will require a pure `PointerLike` value for the array start and the total byte size of the array (e.g. as `index` value).
* Compute `p = p1 && p2 && ... && pn`.
* Compute the total size of the temporary `required_size` (in elements).
diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h
index 293ffa010d14a..8288b814134c8 100644
--- a/flang/include/flang/Lower/ConvertVariable.h
+++ b/flang/include/flang/Lower/ConvertVariable.h
@@ -194,8 +194,8 @@ fir::ExtendedValue genPackArray(Fortran::lower::AbstractConverter &converter,
/// to the given symbol, generate fir.unpack_array operation
/// that reverts the effect of fir.pack_array.
/// \p def is expected to be hlfir.declare operation.
-void genUnpackArray(fir::FirOpBuilder &builder, mlir::Location loc,
- fir::FortranVariableOpInterface def,
+void genUnpackArray(Fortran::lower::AbstractConverter &converter,
+ mlir::Location loc, fir::FortranVariableOpInterface def,
const Fortran::semantics::Symbol &sym);
} // namespace lower
diff --git a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
index 73f388cbab6c9..59c4453d7cb07 100644
--- a/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/include/flang/Optimizer/Dialect/CMakeLists.txt
@@ -28,6 +28,11 @@ set(LLVM_TARGET_DEFINITIONS FirAliasTagOpInterface.td)
mlir_tablegen(FirAliasTagOpInterface.h.inc -gen-op-interface-decls)
mlir_tablegen(FirAliasTagOpInterface.cpp.inc -gen-op-interface-defs)
+set(LLVM_TARGET_DEFINITIONS SafeTempArrayCopyAttrInterface.td)
+mlir_tablegen(SafeTempArrayCopyAttrInterface.h.inc -gen-attr-interface-decls)
+mlir_tablegen(SafeTempArrayCopyAttrInterface.cpp.inc -gen-attr-interface-defs)
+add_public_tablegen_target(FIRSafeTempArrayCopyAttrInterfaceIncGen)
+
set(LLVM_TARGET_DEFINITIONS CanonicalizationPatterns.td)
mlir_tablegen(CanonicalizationPatterns.inc -gen-rewriters)
add_public_tablegen_target(CanonicalizationPatternsIncGen)
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.h b/flang/include/flang/Optimizer/Dialect/FIRAttr.h
index c427a6576b5da..06ec1f57173c3 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.h
@@ -164,4 +164,6 @@ void printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr,
#define GET_ATTRDEF_CLASSES
#include "flang/Optimizer/Dialect/FIRAttr.h.inc"
+#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h"
+
#endif // FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index 8e86d82f38df4..3ebc24951cfff 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -178,4 +178,26 @@ def fir_PackArrayHeuristicsAttr
let assemblyFormat = "`<` $value `>`";
}
+def fir_OpenACCSafeTempArrayCopyAttr : fir_Attr<"OpenACCSafeTempArrayCopy"> {
+ let mnemonic = "acc_safe_temp_array_copy";
+ let description = [{
+ An attribute implementing SafeTempArrayCopyAttrInterface.
+ It specifies whether it is possible to dynamically check
+ if creating a temporary copy of a Fortran array is safe
+ in the context of OpenACC.
+ It also provides the methods to generate those dynamic checks.
+ }];
+}
+
+def fir_OpenMPSafeTempArrayCopyAttr : fir_Attr<"OpenMPSafeTempArrayCopy"> {
+ let mnemonic = "omp_safe_temp_array_copy";
+ let description = [{
+ An attribute implementing SafeTempArrayCopyAttrInterface.
+ It specifies whether it is possible to dynamically check
+ if creating a temporary copy of a Fortran array is safe
+ in the context of OpenMP.
+ It also provides the methods to generate those dynamic checks.
+ }];
+}
+
#endif // FIR_DIALECT_FIR_ATTRS
diff --git a/flang/include/flang/Optimizer/Dialect/FIRDialect.h b/flang/include/flang/Optimizer/Dialect/FIRDialect.h
index ed7c98ec82e2d..fd6f4e01c4d53 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRDialect.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRDialect.h
@@ -44,6 +44,9 @@ void addFIRInlinerExtension(mlir::DialectRegistry ®istry);
// Register implementation of LLVMTranslationDialectInterface.
void addFIRToLLVMIRExtension(mlir::DialectRegistry ®istry);
+void registerFortranTempArrayCopyIsSafeExternalModels(
+ mlir::DialectRegistry ®istry);
+
} // namespace fir
#endif // FORTRAN_OPTIMIZER_DIALECT_FIRDIALECT_H
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.h b/flang/include/flang/Optimizer/Dialect/FIROps.h
index ed301016ad01c..12440dbea0fa4 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.h
@@ -14,6 +14,7 @@
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
+#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index 753e4bd18dc6d..602d6ac2ccf23 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -23,6 +23,7 @@ include "flang/Optimizer/Dialect/FIRTypes.td"
include "flang/Optimizer/Dialect/FIRAttr.td"
include "flang/Optimizer/Dialect/FortranVariableInterface.td"
include "flang/Optimizer/Dialect/FirAliasTagOpInterface.td"
+include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td"
include "mlir/IR/BuiltinAttributes.td"
// Base class for FIR operations.
@@ -3359,6 +3360,14 @@ def fir_PackArrayOp
that is eligible for repacking.
- heuristics attribute specifies conditions when the array repacking
may be optimized.
+ - is_safe is an optional non-empty array of SafeTempArrayCopyAttr
+ attributes. Each attribute implements SafeTempArrayCopyAttrInterface
+ that is used to generate a dynamic predicate value identifying
+ whether the creation of the temporary array copy is safe.
+ For example, if omp.fortran_safe_temp_array_copy attribute
+ is attached, its implementation may generate special code
+ to check if fir.pack_array may be executed by multiple
+ threads, and disallow repacking in this case.
}];
let arguments = (ins AnyBoxedArray:$array, UnitAttr:$stack,
@@ -3367,7 +3376,8 @@ def fir_PackArrayOp
OptionalAttr<UI64Attr>:$min_stride,
DefaultValuedAttr<fir_PackArrayHeuristicsAttr,
"::fir::PackArrayHeuristics::None">:$heuristics,
- Variadic<AnyIntegerType>:$typeparams);
+ Variadic<AnyIntegerType>:$typeparams,
+ OptionalAttr<NonEmptySafeTempArrayCopyArrayAttr>:$is_safe);
let results = (outs AnyBoxedArray:$result);
let assemblyFormat = [{
@@ -3376,7 +3386,7 @@ def fir_PackArrayOp
(`no_copy` $no_copy^)?
(`constraints` custom<PackArrayConstraints>($max_size, $max_element_size, $min_stride)^)?
(`heuristics` $heuristics^)?
- (`typeparams` $typeparams^)?
+ (`typeparams` $typeparams^)? (`is_safe` $is_safe^)?
attr-dict `:` functional-type(operands, results)
}];
@@ -3401,15 +3411,26 @@ def fir_UnpackArrayOp
was allocated.
- no_copy attribute indicates that the temporary array
is not copied into the original temporary array.
+ - is_safe is an optional non-empty array of SafeTempArrayCopyAttr
+ attributes. Each attribute implements SafeTempArrayCopyAttrInterface
+ that is used to generate extra code before any copy-out or
+ deallocation of the temporary happens.
+ For example, if acc.fortran_safe_temp_array_copy attribute
+ is attached, its implementation may generate special code
+ to check if the temporary has been transferred to OpenACC device
+ data environment, and issue a runtime error that the temporary
+ is present on the device while it is about to be deallocated
+ on the host.
}];
let arguments = (ins AnyBoxedArray:$temp, AnyBoxedArray:$original,
- UnitAttr:$stack, UnitAttr:$no_copy);
+ UnitAttr:$stack, UnitAttr:$no_copy,
+ OptionalAttr<NonEmptySafeTempArrayCopyArrayAttr>:$is_safe);
let assemblyFormat = [{
$temp `to` $original
(`stack` $stack^):(`heap`)?
- (`no_copy` $no_copy^)?
+ (`no_copy` $no_copy^)? (`is_safe` $is_safe^)?
attr-dict `:` type($original)
}];
diff --git a/flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h b/flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h
new file mode 100644
index 0000000000000..0b8af4963c809
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h
@@ -0,0 +1,27 @@
+//===- SafeTempArrayCopyAttrInterface.h -------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_DIALECT_SAFETEMPARRAYCOPYATTRINTERFACE_H
+#define FORTRAN_OPTIMIZER_DIALECT_SAFETEMPARRAYCOPYATTRINTERFACE_H
+
+#include "flang/Optimizer/Dialect/FIRAttr.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/OpDefinition.h"
+
+namespace fir {
+class FirOpBuilder;
+}
+
+#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h.inc"
+
+#endif // FORTRAN_OPTIMIZER_DIALECT_SAFETEMPARRAYCOPYATTRINTERFACE_H
diff --git a/flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td b/flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td
new file mode 100644
index 0000000000000..e8b09e95b0a21
--- /dev/null
+++ b/flang/include/flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td
@@ -0,0 +1,81 @@
+//===- SafeTempArrayCopyAttrInterface.td -------------------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines SafeTempArrayCopyAttrInterface and a generic attribute
+/// SafeTempArrayCopyAttr promising the SafeTempArrayCopyAttrInterface.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_SAFETEMPARRAYCOPYATTRINTERFACE_TD
+#define FORTRAN_SAFETEMPARRAYCOPYATTRINTERFACE_TD
+
+include "mlir/IR/OpBase.td"
+
+def SafeTempArrayCopyAttrInterface
+ : AttrInterface<"SafeTempArrayCopyAttrInterface"> {
+ let cppNamespace = "::fir";
+ let description = [{
+ Interface for attributes defining whether creation of a temporary
+ copy of a Fortran array is safe and/or how to produce proper
+ dynamic checks to avoid it, if it is unsafe.
+ }];
+
+ let methods =
+ [StaticInterfaceMethod<
+ /*desc=*/[{
+ Returns true iff the usage of the temporary array copy
+ can be made safe applying some dynamic checks.
+ }],
+ /*retTy=*/"bool",
+ /*methodName=*/"isDynamicallySafe",
+ /*args=*/(ins)>,
+ StaticInterfaceMethod<
+ /*desc=*/[{
+ Generate FIR that produces an i1 Value indicating
+ whether the creation of the temporary array copy is safe.
+ \p array is a definition of the original array.
+ The implementation may assume that \p array is present
+ (though, it may be empty).
+ }],
+ /*retTy=*/"mlir::Value",
+ /*methodName=*/"genDynamicCheck",
+ /*args=*/
+ (ins "::mlir::Location":$loc, "::fir::FirOpBuilder &":$builder,
+ "::mlir::Value":$array)>,
+ StaticInterfaceMethod<
+ /*desc=*/[{
+ This method allows inserting any FIR right before the optional
+ copy-out (from \p temp to \p array) and the deallocation
+ of the temporary array (implying that the temporary copy was
+ actually created).
+ }],
+ /*retTy=*/"void",
+ /*methodName=*/"registerTempDeallocation",
+ /*args=*/
+ (ins "::mlir::Location":$loc, "::fir::FirOpBuilder &":$builder,
+ "::mlir::Value":$array, "::mlir::Value":$temp)>,
+ ];
+}
+
+def SafeTempArrayCopyAttr
+ : ConfinedAttr<
+ AnyAttr, [PromisedAttrInterface<SafeTempArrayCopyAttrInterface>]> {
+ let description = [{
+ Generic attribute implementing or promising
+ the `SafeTempArrayCopyAttrInterface` interface.
+ }];
+}
+
+def SafeTempArrayCopyArrayAttr
+ : TypedArrayAttrBase<SafeTempArrayCopyAttr,
+ "array of SafeTempArrayCopyAttr attributes">;
+
+def NonEmptySafeTempArrayCopyArrayAttr
+ : ConfinedAttr<SafeTempArrayCopyArrayAttr, [ArrayMinCount<1>]>;
+
+#endif // FORTRAN_SAFETEMPARRAYCOPYATTRINTERFACE_TD
diff --git a/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h b/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h
index efaddd72ebbf2..36c31d3381705 100644
--- a/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h
+++ b/flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h
@@ -17,6 +17,14 @@ namespace fir::acc {
void registerOpenACCExtensions(mlir::DialectRegistry ®istry);
+/// Register external models for FIR attributes related to OpenACC.
+void registerAttrsExtensions(mlir::DialectRegistry ®istry);
+
+/// Register all dialects whose operations may be created
+/// by the transformational attributes.
+void registerTransformationalAttrsDependentDialects(
+ mlir::DialectRegistry ®istry);
+
} // namespace fir::acc
#endif // FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_
diff --git a/flang/include/flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h b/flang/include/flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h
new file mode 100644
index 0000000000000..b0fa1d16cb2bd
--- /dev/null
+++ b/flang/include/flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h
@@ -0,0 +1,30 @@
+//===- RegisterOpenMPExtensions.h - OpenMP Extension Registration -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FLANG_OPTIMIZER_OPENMP_SUPPORT_REGISTEROPENMPEXTENSIONS_H_
+#define FLANG_OPTIMIZER_OPENMP_SUPPORT_REGISTEROPENMPEXTENSIONS_H_
+
+namespace mlir {
+class DialectRegistry;
+} // namespace mlir
+
+namespace fir::omp {
+
+void registerOpenMPExtensions(mlir::DialectRegistry ®istry);
+
+/// Register external models for FIR attributes related to OpenMP.
+void registerAttrsExtensions(mlir::DialectRegistry ®istry);
+
+/// Register all dialects whose operations may be created
+/// by the transformational attributes.
+void registerTransformationalAttrsDependentDialects(
+ mlir::DialectRegistry ®istry);
+
+} // namespace fir::omp
+
+#endif // FLANG_OPTIMIZER_OPENMP_SUPPORT_REGISTEROPENMPEXTENSIONS_H_
diff --git a/flang/include/flang/Optimizer/Support/InitFIR.h b/flang/include/flang/Optimizer/Support/InitFIR.h
index f509fdfcf4918..4c57e01c28c93 100644
--- a/flang/include/flang/Optimizer/Support/InitFIR.h
+++ b/flang/include/flang/Optimizer/Support/InitFIR.h
@@ -18,6 +18,7 @@
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/HLFIR/HLFIRDialect.h"
#include "flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h"
+#include "flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h"
#include "mlir/Conversion/Passes.h"
#include "mlir/Dialect/Affine/Passes.h"
#include "mlir/Dialect/Complex/IR/Complex.h"
@@ -67,6 +68,7 @@ inline void addFIRExtensions(mlir::DialectRegistry ®istry,
addFIRToLLVMIRExtension(registry);
cuf::registerCUFDialectTranslation(registry);
fir::acc::registerOpenACCExtensions(registry);
+ fir::omp::registerOpenMPExtensions(registry);
}
inline void loadNonCodegenDialects(mlir::MLIRContext &context) {
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index e8a098613e26f..3659e7d9d8550 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -38,6 +38,7 @@ add_flang_library(flangFrontend
HLFIRTransforms
flangPasses
FIROpenACCSupport
+ FIROpenMPSupport
FlangOpenMPTransforms
LINK_COMPONENTS
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index bd2c0632cb35d..7d079623f4326 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -203,6 +203,7 @@ bool CodeGenAction::beginSourceFileAction() {
fir::support::registerLLVMTranslation(*mlirCtx);
mlir::DialectRegistry registry;
fir::acc::registerOpenACCExtensions(registry);
+ fir::omp::registerOpenMPExtensions(registry);
mlirCtx->appendDialectRegistry(registry);
const llvm::TargetMachine &targetMachine = ci.getTargetMachine();
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 366ff328bfa27..b277c0d7040a7 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1040,6 +1040,21 @@ static bool needsRepack(Fortran::lower::AbstractConverter &converter,
return true;
}
+static mlir::ArrayAttr
+getSafeRepackAttrs(Fortran::lower::AbstractConverter &converter) {
+ llvm::SmallVector<mlir::Attribute> attrs;
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+ const auto &langFeatures = converter.getFoldingContext().languageFeatures();
+ if (langFeatures.IsEnabled(Fortran::common::LanguageFeature::OpenACC))
+ attrs.push_back(
+ fir::OpenACCSafeTempArrayCopyAttr::get(builder.getContext()));
+ if (langFeatures.IsEnabled(Fortran::common::LanguageFeature::OpenMP))
+ attrs.push_back(
+ fir::OpenMPSafeTempArrayCopyAttr::get(builder.getContext()));
+
+ return attrs.empty() ? mlir::ArrayAttr{} : builder.getArrayAttr(attrs);
+}
+
/// Instantiate a local variable. Precondition: Each variable will be visited
/// such that if its properties depend on other variables, the variables upon
/// which its properties depend will already have been visited.
@@ -1109,15 +1124,15 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
});
}
} else if (var.hasSymbol() && needsRepack(converter, var.getSymbol())) {
- auto *builder = &converter.getFirOpBuilder();
+ auto *converterPtr = &converter;
mlir::Location loc = converter.getCurrentLocation();
auto *sym = &var.getSymbol();
std::optional<fir::FortranVariableOpInterface> varDef =
symMap.lookupVariableDefinition(*sym);
assert(varDef && "cannot find defining operation for an array that needs "
"to be repacked");
- converter.getFctCtx().attachCleanup([builder, loc, varDef, sym]() {
- Fortran::lower::genUnpackArray(*builder, loc, *varDef, *sym);
+ converter.getFctCtx().attachCleanup([converterPtr, loc, varDef, sym]() {
+ Fortran::lower::genUnpackArray(*converterPtr, loc, *varDef, *sym);
});
}
}
@@ -2648,7 +2663,7 @@ Fortran::lower::genPackArray(Fortran::lower::AbstractConverter &converter,
/*max_size=*/mlir::IntegerAttr{},
/*max_element_size=*/mlir::IntegerAttr{},
/*min_stride=*/mlir::IntegerAttr{}, fir::PackArrayHeuristics::None,
- elidedLenParams);
+ elidedLenParams, getSafeRepackAttrs(converter));
mlir::Value newBase = packOp.getResult();
return exv.match(
@@ -2663,10 +2678,10 @@ Fortran::lower::genPackArray(Fortran::lower::AbstractConverter &converter,
});
}
-void Fortran::lower::genUnpackArray(fir::FirOpBuilder &builder,
- mlir::Location loc,
- fir::FortranVariableOpInterface def,
- const Fortran::semantics::Symbol &sym) {
+void Fortran::lower::genUnpackArray(
+ Fortran::lower::AbstractConverter &converter, mlir::Location loc,
+ fir::FortranVariableOpInterface def,
+ const Fortran::semantics::Symbol &sym) {
// Subtle: rely on the fact that the memref of the defining
// hlfir.declare is a result of fir.pack_array.
// Alternatively, we can track the pack operation for a symbol
@@ -2681,5 +2696,7 @@ void Fortran::lower::genUnpackArray(fir::FirOpBuilder &builder,
bool stackAlloc = packOp.getStack();
// Avoid copy-out for 'intent(in)' variables.
bool noCopy = Fortran::semantics::IsIntentIn(sym);
- builder.create<fir::UnpackArrayOp>(loc, temp, original, stackAlloc, noCopy);
+ fir::FirOpBuilder &builder = converter.getFirOpBuilder();
+ builder.create<fir::UnpackArrayOp>(loc, temp, original, stackAlloc, noCopy,
+ getSafeRepackAttrs(converter));
}
diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index f730c7fd03948..e476ad798360a 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -23,6 +23,8 @@ add_flang_library(FIRCodeGen
FIRBuilder
FIRDialect
FIRDialectSupport
+ FIROpenACCSupport
+ FIROpenMPSupport
FIRSupport
LINK_COMPONENTS
diff --git a/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp b/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp
index 0acc034c47152..7deed3d44ae5b 100644
--- a/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp
+++ b/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp
@@ -38,6 +38,8 @@
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h"
+#include "flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
@@ -105,9 +107,37 @@ static bool canAllocateTempOnStack(mlir::Value box) {
return !fir::isPolymorphicType(box.getType());
}
+/// Return true if array repacking is safe either statically
+/// (there are no 'is_safe' attributes) or dynamically
+/// (neither of the 'is_safe' attributes claims 'isDynamicallySafe() == false').
+/// \p op is either fir.pack_array or fir.unpack_array.
+template <typename OP>
+static bool repackIsSafe(OP op) {
+ bool isSafe = true;
+ if (auto isSafeAttrs = op.getIsSafe()) {
+ // We currently support only the attributes for which
+ // isDynamicallySafe() returns false.
+ for (auto attr : *isSafeAttrs) {
+ auto iface = mlir::cast<fir::SafeTempArrayCopyAttrInterface>(attr);
+ if (iface.isDynamicallySafe())
+ TODO(op.getLoc(), "dynamically safe array repacking");
+ else
+ isSafe = false;
+ }
+ }
+ return isSafe;
+}
+
mlir::LogicalResult
PackArrayConversion::matchAndRewrite(fir::PackArrayOp op,
mlir::PatternRewriter &rewriter) const {
+ mlir::Value box = op.getArray();
+ // If repacking is not safe, then just use the original box.
+ if (!repackIsSafe(op)) {
+ rewriter.replaceOp(op, box);
+ return mlir::success();
+ }
+
mlir::Location loc = op.getLoc();
fir::FirOpBuilder builder(rewriter, op.getOperation());
if (op.getMaxSize() || op.getMaxElementSize() || op.getMinStride())
@@ -115,7 +145,6 @@ PackArrayConversion::matchAndRewrite(fir::PackArrayOp op,
if (op.getHeuristics() != fir::PackArrayHeuristics::None)
TODO(loc, "fir.pack_array with heuristics");
- mlir::Value box = op.getArray();
auto boxType = mlir::cast<fir::BaseBoxType>(box.getType());
// For now we have to always check if the box is present.
@@ -181,6 +210,7 @@ PackArrayConversion::genRepackedBox(fir::FirOpBuilder &builder,
mlir::Location loc, fir::PackArrayOp op) {
mlir::OpBuilder::InsertionGuard guard(builder);
mlir::Value box = op.getArray();
+
llvm::SmallVector<mlir::Value> typeParams(op.getTypeparams().begin(),
op.getTypeparams().end());
auto boxType = mlir::cast<fir::BaseBoxType>(box.getType());
@@ -268,6 +298,12 @@ PackArrayConversion::genRepackedBox(fir::FirOpBuilder &builder,
mlir::LogicalResult
UnpackArrayConversion::matchAndRewrite(fir::UnpackArrayOp op,
mlir::PatternRewriter &rewriter) const {
+ // If repacking is not safe, then just remove the operation.
+ if (!repackIsSafe(op)) {
+ rewriter.eraseOp(op);
+ return mlir::success();
+ }
+
mlir::Location loc = op.getLoc();
fir::FirOpBuilder builder(rewriter, op.getOperation());
mlir::Type predicateType = builder.getI1Type();
@@ -325,6 +361,11 @@ class LowerRepackArraysPass
mlir::GreedySimplifyRegionLevel::Disabled;
(void)applyPatternsGreedily(module, std::move(patterns), config);
}
+
+ void getDependentDialects(mlir::DialectRegistry ®istry) const override {
+ fir::acc::registerTransformationalAttrsDependentDialects(registry);
+ fir::omp::registerTransformationalAttrsDependentDialects(registry);
+ }
};
} // anonymous namespace
diff --git a/flang/lib/Optimizer/Dialect/CMakeLists.txt b/flang/lib/Optimizer/Dialect/CMakeLists.txt
index 61f9c6110491e..f6476d6ef3fe8 100644
--- a/flang/lib/Optimizer/Dialect/CMakeLists.txt
+++ b/flang/lib/Optimizer/Dialect/CMakeLists.txt
@@ -9,10 +9,12 @@ add_flang_library(FIRDialect
FirAliasTagOpInterface.cpp
FortranVariableInterface.cpp
Inliner.cpp
+ SafeTempArrayCopyAttrInterface.cpp
DEPENDS
CanonicalizationPatternsIncGen
FIROpsIncGen
+ FIRSafeTempArrayCopyAttrInterfaceIncGen
CUFAttrsIncGen
intrinsics_gen
diff --git a/flang/lib/Optimizer/Dialect/FIRAttr.cpp b/flang/lib/Optimizer/Dialect/FIRAttr.cpp
index d190b307dc7f2..a1a16e589e8e3 100644
--- a/flang/lib/Optimizer/Dialect/FIRAttr.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRAttr.cpp
@@ -296,9 +296,9 @@ void fir::printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr,
//===----------------------------------------------------------------------===//
void FIROpsDialect::registerAttributes() {
- addAttributes<ClosedIntervalAttr, ExactTypeAttr,
- FortranProcedureFlagsEnumAttr, FortranVariableFlagsAttr,
- LowerBoundAttr, PointIntervalAttr, RealAttr, ReduceAttr,
- SubclassAttr, UpperBoundAttr, LocationKindAttr,
- LocationKindArrayAttr, PackArrayHeuristicsAttr>();
+ addAttributes<ClosedIntervalAttr, ExactTypeAttr, LowerBoundAttr,
+ PointIntervalAttr, RealAttr, SubclassAttr, UpperBoundAttr,
+#define GET_ATTRDEF_LIST
+#include "flang/Optimizer/Dialect/FIRAttr.cpp.inc"
+ >();
}
diff --git a/flang/lib/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.cpp b/flang/lib/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.cpp
new file mode 100644
index 0000000000000..0786de7d49551
--- /dev/null
+++ b/flang/lib/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.cpp
@@ -0,0 +1,15 @@
+//===-- SafeTempArrayCopyAttrInterface.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h"
+
+#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.cpp.inc"
diff --git a/flang/lib/Optimizer/OpenACC/CMakeLists.txt b/flang/lib/Optimizer/OpenACC/CMakeLists.txt
index 4a09133fc110d..89dbd1f551f16 100644
--- a/flang/lib/Optimizer/OpenACC/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenACC/CMakeLists.txt
@@ -1,6 +1,7 @@
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
add_flang_library(FIROpenACCSupport
+ FIROpenACCAttributes.cpp
FIROpenACCTypeInterfaces.cpp
RegisterOpenACCExtensions.cpp
diff --git a/flang/lib/Optimizer/OpenACC/FIROpenACCAttributes.cpp b/flang/lib/Optimizer/OpenACC/FIROpenACCAttributes.cpp
new file mode 100644
index 0000000000000..5d5dd3dab8546
--- /dev/null
+++ b/flang/lib/Optimizer/OpenACC/FIROpenACCAttributes.cpp
@@ -0,0 +1,67 @@
+//===-- FIROpenACCAttributes.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements attribute interfaces that are promised by FIR
+/// dialect attributes related to OpenACC.
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/FIRAttr.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+
+namespace fir::acc {
+class FortranSafeTempArrayCopyAttrImpl
+ : public fir::SafeTempArrayCopyAttrInterface::FallbackModel<
+ FortranSafeTempArrayCopyAttrImpl> {
+public:
+ // SafeTempArrayCopyAttrInterface interface methods.
+ static bool isDynamicallySafe() { return false; }
+ static mlir::Value genDynamicCheck(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ mlir::Value array) {
+ TODO(loc, "fir::acc::FortranSafeTempArrayCopyAttrImpl::genDynamicCheck()");
+ return nullptr;
+ }
+ static void registerTempDeallocation(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ mlir::Value array, mlir::Value temp) {
+ TODO(loc, "fir::acc::FortranSafeTempArrayCopyAttrImpl::"
+ "registerTempDeallocation()");
+ }
+
+ // Extra helper methods.
+
+ /// Attach the implementation to fir::OpenACCSafeTempArrayCopyAttr.
+ static void registerExternalModel(mlir::DialectRegistry ®istry);
+
+ /// If the methods above create any new operations, this method
+ /// must register all the corresponding dialect.
+ static void getDependentDialects(mlir::DialectRegistry ®istry) {}
+};
+
+void FortranSafeTempArrayCopyAttrImpl::registerExternalModel(
+ mlir::DialectRegistry ®istry) {
+ registry.addExtension(
+ +[](mlir::MLIRContext *ctx, fir::FIROpsDialect *dialect) {
+ fir::OpenACCSafeTempArrayCopyAttr::attachInterface<
+ FortranSafeTempArrayCopyAttrImpl>(*ctx);
+ });
+}
+
+void registerAttrsExtensions(mlir::DialectRegistry ®istry) {
+ FortranSafeTempArrayCopyAttrImpl::registerExternalModel(registry);
+}
+
+void registerTransformationalAttrsDependentDialects(
+ mlir::DialectRegistry ®istry) {
+ FortranSafeTempArrayCopyAttrImpl::getDependentDialects(registry);
+}
+
+} // namespace fir::acc
diff --git a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp
index 184a264c64325..16115c7cb6e59 100644
--- a/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp
+++ b/flang/lib/Optimizer/OpenACC/RegisterOpenACCExtensions.cpp
@@ -32,6 +32,7 @@ void registerOpenACCExtensions(mlir::DialectRegistry ®istry) {
fir::LLVMPointerType::attachInterface<
OpenACCPointerLikeModel<fir::LLVMPointerType>>(*ctx);
});
+ registerAttrsExtensions(registry);
}
} // namespace fir::acc
diff --git a/flang/lib/Optimizer/OpenMP/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
index 3acf143594356..62a2fe377053b 100644
--- a/flang/lib/Optimizer/OpenMP/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenMP/CMakeLists.txt
@@ -35,3 +35,5 @@ add_flang_library(FlangOpenMPTransforms
MLIRTransformUtils
${dialect_libs}
)
+
+add_subdirectory(Support)
diff --git a/flang/lib/Optimizer/OpenMP/Support/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/Support/CMakeLists.txt
new file mode 100644
index 0000000000000..dee35e4f2c5a4
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/Support/CMakeLists.txt
@@ -0,0 +1,20 @@
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+add_flang_library(FIROpenMPSupport
+ FIROpenMPAttributes.cpp
+ RegisterOpenMPExtensions.cpp
+
+ DEPENDS
+ FIRBuilder
+ FIRDialect
+
+ LINK_LIBS
+ FIRBuilder
+ FIRDialect
+
+ MLIR_DEPS
+ MLIROpenMPDialect
+
+ MLIR_LIBS
+ MLIROpenMPDialect
+)
diff --git a/flang/lib/Optimizer/OpenMP/Support/FIROpenMPAttributes.cpp b/flang/lib/Optimizer/OpenMP/Support/FIROpenMPAttributes.cpp
new file mode 100644
index 0000000000000..e343bbc2ee019
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/Support/FIROpenMPAttributes.cpp
@@ -0,0 +1,69 @@
+//===-- FIROpenMPAttributes.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file implements attribute interfaces that are promised by FIR
+/// dialect attributes related to OpenMP.
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/Dialect/FIRAttr.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+
+namespace fir::omp {
+class FortranSafeTempArrayCopyAttrImpl
+ : public fir::SafeTempArrayCopyAttrInterface::FallbackModel<
+ FortranSafeTempArrayCopyAttrImpl> {
+public:
+ // SafeTempArrayCopyAttrInterface interface methods.
+ static bool isDynamicallySafe() { return false; }
+
+ static mlir::Value genDynamicCheck(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ mlir::Value array) {
+ TODO(loc, "fir::omp::FortranSafeTempArrayCopyAttrImpl::genDynamicCheck()");
+ return nullptr;
+ }
+
+ static void registerTempDeallocation(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ mlir::Value array, mlir::Value temp) {
+ TODO(loc, "fir::omp::FortranSafeTempArrayCopyAttrImpl::"
+ "registerTempDeallocation()");
+ }
+
+ // Extra helper methods.
+
+ /// Attach the implementation to fir::OpenMPSafeTempArrayCopyAttr.
+ static void registerExternalModel(mlir::DialectRegistry ®istry);
+
+ /// If the methods above create any new operations, this method
+ /// must register all the corresponding dialect.
+ static void getDependentDialects(mlir::DialectRegistry ®istry) {}
+};
+
+void FortranSafeTempArrayCopyAttrImpl::registerExternalModel(
+ mlir::DialectRegistry ®istry) {
+ registry.addExtension(
+ +[](mlir::MLIRContext *ctx, fir::FIROpsDialect *dialect) {
+ fir::OpenMPSafeTempArrayCopyAttr::attachInterface<
+ FortranSafeTempArrayCopyAttrImpl>(*ctx);
+ });
+}
+
+void registerAttrsExtensions(mlir::DialectRegistry ®istry) {
+ FortranSafeTempArrayCopyAttrImpl::registerExternalModel(registry);
+}
+
+void registerTransformationalAttrsDependentDialects(
+ mlir::DialectRegistry ®istry) {
+ FortranSafeTempArrayCopyAttrImpl::getDependentDialects(registry);
+}
+
+} // namespace fir::omp
diff --git a/flang/lib/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.cpp b/flang/lib/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.cpp
new file mode 100644
index 0000000000000..2495d54bf0174
--- /dev/null
+++ b/flang/lib/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.cpp
@@ -0,0 +1,20 @@
+//===-- RegisterOpenMPExtensions.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Registration for OpenMP extensions as applied to FIR dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/OpenMP/Support/RegisterOpenMPExtensions.h"
+
+namespace fir::omp {
+void registerOpenMPExtensions(mlir::DialectRegistry ®istry) {
+ registerAttrsExtensions(registry);
+}
+
+} // namespace fir::omp
diff --git a/flang/test/Lower/repack-arrays-safe.f90 b/flang/test/Lower/repack-arrays-safe.f90
new file mode 100644
index 0000000000000..1ec422eb68415
--- /dev/null
+++ b/flang/test/Lower/repack-arrays-safe.f90
@@ -0,0 +1,17 @@
+! Test that fir.acc_safe_temp_array_copy and fir.omp_safe_temp_array_copy
+! are properly attached to fir.[un]pack_array by the lowering.
+
+! RUN: bbc -emit-hlfir -fopenacc -frepack-arrays %s -o - | FileCheck --check-prefixes=ALL,ACC %s
+! RUN: bbc -emit-hlfir -fopenmp -frepack-arrays %s -o - | FileCheck --check-prefixes=ALL,OMP %s
+! RUN: bbc -emit-hlfir -fopenacc -fopenmp -frepack-arrays %s -o - | FileCheck --check-prefixes=ALL,ACCOMP %s
+
+subroutine test(x)
+ real :: x(:)
+end subroutine test
+! ALL-LABEL: func.func @_QPtest(
+! ACC: %[[VAL_2:.*]] = fir.pack_array{{.*}}is_safe [#fir.acc_safe_temp_array_copy]
+! ACC: fir.unpack_array{{.*}}is_safe [#fir.acc_safe_temp_array_copy]
+! OMP: %[[VAL_2:.*]] = fir.pack_array{{.*}}is_safe [#fir.omp_safe_temp_array_copy]
+! OMP: fir.unpack_array{{.*}}is_safe [#fir.omp_safe_temp_array_copy]
+! ACCOMP: %[[VAL_2:.*]] = fir.pack_array{{.*}}is_safe [#fir.acc_safe_temp_array_copy, #fir.omp_safe_temp_array_copy]
+! ACCOMP: fir.unpack_array{{.*}}is_safe [#fir.acc_safe_temp_array_copy, #fir.omp_safe_temp_array_copy]
diff --git a/flang/test/Transforms/lower-repack-arrays-openacc.fir b/flang/test/Transforms/lower-repack-arrays-openacc.fir
new file mode 100644
index 0000000000000..148116160d42e
--- /dev/null
+++ b/flang/test/Transforms/lower-repack-arrays-openacc.fir
@@ -0,0 +1,17 @@
+// RUN: fir-opt --lower-repack-arrays %s | FileCheck %s
+
+// Test the current implementation of #fir.acc_safe_temp_array_copy attribute.
+// It results in removal of fir.[un]pack_array operations.
+func.func @_QPtest(%arg0: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"}) {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.pack_array %arg0 heap whole is_safe [#fir.acc_safe_temp_array_copy] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
+ %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtestEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+ fir.unpack_array %1 to %arg0 heap is_safe [#fir.acc_safe_temp_array_copy] : !fir.box<!fir.array<?xf32>>
+ return
+}
+// CHECK-LABEL: func.func @_QPtest(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"}) {
+// CHECK-NEXT: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK-NEXT: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFtestEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
diff --git a/flang/test/Transforms/lower-repack-arrays-openmp.fir b/flang/test/Transforms/lower-repack-arrays-openmp.fir
new file mode 100644
index 0000000000000..ac49769b18fc8
--- /dev/null
+++ b/flang/test/Transforms/lower-repack-arrays-openmp.fir
@@ -0,0 +1,17 @@
+// RUN: fir-opt --lower-repack-arrays %s | FileCheck %s
+
+// Test the current implementation of #fir.omp_safe_temp_array_copy attribute.
+// It results in removal of fir.[un]pack_array operations.
+func.func @_QPtest(%arg0: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"}) {
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.pack_array %arg0 heap whole is_safe [#fir.omp_safe_temp_array_copy] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<!fir.array<?xf32>>
+ %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtestEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+ fir.unpack_array %1 to %arg0 heap is_safe [#fir.omp_safe_temp_array_copy] : !fir.box<!fir.array<?xf32>>
+ return
+}
+// CHECK-LABEL: func.func @_QPtest(
+// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"}) {
+// CHECK-NEXT: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK-NEXT: %[[VAL_2:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QFtestEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?xf32>>
+// CHECK-NEXT: return
+// CHECK-NEXT: }
diff --git a/flang/tools/bbc/CMakeLists.txt b/flang/tools/bbc/CMakeLists.txt
index f950f03920d3f..469266cc81558 100644
--- a/flang/tools/bbc/CMakeLists.txt
+++ b/flang/tools/bbc/CMakeLists.txt
@@ -21,6 +21,7 @@ target_link_libraries(bbc PRIVATE
FIRDialect
FIRDialectSupport
FIROpenACCSupport
+ FIROpenMPSupport
FIRSupport
FIRTransforms
FIRBuilder
diff --git a/flang/tools/fir-lsp-server/CMakeLists.txt b/flang/tools/fir-lsp-server/CMakeLists.txt
index 6f095e24524b7..86cde79a66830 100644
--- a/flang/tools/fir-lsp-server/CMakeLists.txt
+++ b/flang/tools/fir-lsp-server/CMakeLists.txt
@@ -12,6 +12,7 @@ target_link_libraries(fir-lsp-server PRIVATE
CUFDialect
FIRDialect
FIROpenACCSupport
+ FIROpenMPSupport
HLFIRDialect)
mlir_target_link_libraries(fir-lsp-server PRIVATE
diff --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt
index efbde329b8b8c..9c123530d7cae 100644
--- a/flang/tools/fir-opt/CMakeLists.txt
+++ b/flang/tools/fir-opt/CMakeLists.txt
@@ -21,6 +21,7 @@ target_link_libraries(fir-opt PRIVATE
HLFIRDialect
HLFIRTransforms
FIROpenACCSupport
+ FIROpenMPSupport
FlangOpenMPTransforms
FIRAnalysis
${test_libs}
diff --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt
index c277cdbf167b6..3b8040a15b140 100644
--- a/flang/tools/tco/CMakeLists.txt
+++ b/flang/tools/tco/CMakeLists.txt
@@ -19,6 +19,7 @@ target_link_libraries(tco PRIVATE
HLFIRTransforms
flangPasses
FIROpenACCSupport
+ FIROpenMPSupport
FlangOpenMPTransforms
FortranSupport
)
>From d73d379332d65f2efb0ce2353a9b647bb0e26ac1 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Thu, 3 Apr 2025 22:18:25 -0700
Subject: [PATCH 2/2] [WIP] Resolve cyclic dependency between FIROpenACCSupport
and FIRCodeGen.
I would like to move FIRCodeGen passes into its own component
library, and keep the FIRCodeGenDialect separate.
---
flang/lib/Frontend/CMakeLists.txt | 1 +
flang/lib/Optimizer/CodeGen/CMakeLists.txt | 25 ++++++++++++++++---
flang/lib/Optimizer/OpenACC/CMakeLists.txt | 3 +--
flang/lib/Optimizer/Transforms/CMakeLists.txt | 1 +
flang/tools/fir-opt/CMakeLists.txt | 1 +
flang/tools/tco/CMakeLists.txt | 1 +
flang/unittests/Optimizer/CMakeLists.txt | 2 +-
7 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt
index 3659e7d9d8550..96ba27ad418f7 100644
--- a/flang/lib/Frontend/CMakeLists.txt
+++ b/flang/lib/Frontend/CMakeLists.txt
@@ -33,6 +33,7 @@ add_flang_library(flangFrontend
FIRSupport
FIRBuilder
FIRCodeGen
+ FIRCodeGenDialect
FIRTransforms
HLFIRDialect
HLFIRTransforms
diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index e476ad798360a..caa4fa9f73eb7 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -1,6 +1,23 @@
+add_flang_library(FIRCodeGenDialect
+ CGOps.cpp
+
+ PARTIAL_SOURCES_INTENDED
+
+ DEPENDS
+ CGOpsIncGen
+
+ LINK_LIBS
+ FIRDialect
+ MLIRIR
+
+ LINK_COMPONENTS
+ AsmParser
+ AsmPrinter
+
+ )
+
add_flang_library(FIRCodeGen
BoxedProcedure.cpp
- CGOps.cpp
CodeGen.cpp
CodeGenOpenMP.cpp
FIROpPatterns.cpp
@@ -11,6 +28,8 @@ add_flang_library(FIRCodeGen
TargetRewrite.cpp
TypeConverter.cpp
+ PARTIAL_SOURCES_INTENDED
+
DEPENDS
CUFAttrs
FIRDialect
@@ -21,6 +40,7 @@ add_flang_library(FIRCodeGen
CUFAttrs
FIRAnalysis
FIRBuilder
+ FIRCodeGenDialect
FIRDialect
FIRDialectSupport
FIROpenACCSupport
@@ -28,8 +48,6 @@ add_flang_library(FIRCodeGen
FIRSupport
LINK_COMPONENTS
- AsmParser
- AsmPrinter
Remarks
TargetParser
@@ -47,4 +65,5 @@ add_flang_library(FIRCodeGen
MLIRLLVMToLLVMIRTranslation
MLIRTargetLLVMIRExport
MLIRVectorToLLVM
+
)
diff --git a/flang/lib/Optimizer/OpenACC/CMakeLists.txt b/flang/lib/Optimizer/OpenACC/CMakeLists.txt
index 89dbd1f551f16..ef67ab1549537 100644
--- a/flang/lib/Optimizer/OpenACC/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenACC/CMakeLists.txt
@@ -7,7 +7,6 @@ add_flang_library(FIROpenACCSupport
DEPENDS
FIRBuilder
- FIRCodeGen
FIRDialect
FIRDialectSupport
FIRSupport
@@ -15,7 +14,7 @@ add_flang_library(FIROpenACCSupport
LINK_LIBS
FIRBuilder
- FIRCodeGen
+ FIRCodeGenDialect
FIRDialect
FIRDialectSupport
FIRSupport
diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt
index ca08e4607e019..170b6e2cca225 100644
--- a/flang/lib/Optimizer/Transforms/CMakeLists.txt
+++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt
@@ -47,6 +47,7 @@ add_flang_library(FIRTransforms
FIRAnalysis
FIRBuilder
FIRCodeGen
+ FIRCodeGenDialect
FIRDialect
FIRDialectSupport
FIRSupport
diff --git a/flang/tools/fir-opt/CMakeLists.txt b/flang/tools/fir-opt/CMakeLists.txt
index 9c123530d7cae..4ee9752727b87 100644
--- a/flang/tools/fir-opt/CMakeLists.txt
+++ b/flang/tools/fir-opt/CMakeLists.txt
@@ -18,6 +18,7 @@ target_link_libraries(fir-opt PRIVATE
FIRSupport
FIRTransforms
FIRCodeGen
+ FIRCodeGenDialect
HLFIRDialect
HLFIRTransforms
FIROpenACCSupport
diff --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt
index 3b8040a15b140..ab2aab2cf99a6 100644
--- a/flang/tools/tco/CMakeLists.txt
+++ b/flang/tools/tco/CMakeLists.txt
@@ -10,6 +10,7 @@ target_link_libraries(tco PRIVATE
CUFAttrs
CUFDialect
FIRCodeGen
+ FIRCodeGenDialect
FIRDialect
FIRDialectSupport
FIRSupport
diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index 1289341619118..a84d54d96102a 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -8,7 +8,7 @@ set(LLVM_LINK_COMPONENTS
set(LIBS
CUFDialect
FIRBuilder
- FIRCodeGen
+ FIRCodeGenDialect
FIRDialect
FIRDialectSupport
FIRSupport
More information about the flang-commits
mailing list