Skip to content

Commit 8086dde

Browse files
committed
[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.
1 parent a62b9b3 commit 8086dde

35 files changed

+542
-26
lines changed

flang/docs/ArrayRepacking.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ Arguments:
205205
* `max-element-size` - constant integer attribute specifying the maximum byte element-size of an array that is eligible for repacking.
206206
* `min-stride` - constant integer attribute specifying the minimum byte stride of the innermost dimension of an array that is eligible for repacking.
207207
* `typeparams` - type parameters of the element type.
208-
* `*.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.
208+
* `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.
209209

210210
Memory effects are conservative, assuming that an allocation and copy may happen:
211211

@@ -243,7 +243,7 @@ Memory effects are conservative, assuming that a copy and deallocation may happe
243243

244244
### New attribute interface
245245

246-
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:
246+
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:
247247

248248
```C
249249
repacking_is_safe = omp_get_num_team() == 1 && omp_get_num_threads() == 1;
@@ -297,15 +297,15 @@ end program main
297297

298298
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.
299299

300-
[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.
300+
`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`
301301

302302
#### Alternatives/additions to the attribute interface
303303

304304
The following ideas were expressed during the review, and they are worth considering.
305305

306306
| |
307307
| - |
308-
| 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. |
308+
| 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. |
309309
| 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). |
310310
| 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. |
311311

@@ -373,7 +373,7 @@ Lowering of the new operations (after all the optimizations) might be done in a
373373
`fir.pack_array` lowering might be done in the following steps:
374374

375375
* 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.
376-
* If there are attributes implementing `TempCopyIsSafe` attribute interface, then use the interface method to generate boolean predicates for each such attribute: `p2`, ..., `pn`.
376+
* If there are attributes implementing `fir::SafeTempArrayCopyAttrInterface` attribute interface, then use the interface method to generate boolean predicates for each such attribute: `p2`, ..., `pn`.
377377
* [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).
378378
* Compute `p = p1 && p2 && ... && pn`.
379379
* Compute the total size of the temporary `required_size` (in elements).

flang/include/flang/Lower/ConvertVariable.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ fir::ExtendedValue genPackArray(Fortran::lower::AbstractConverter &converter,
194194
/// to the given symbol, generate fir.unpack_array operation
195195
/// that reverts the effect of fir.pack_array.
196196
/// \p def is expected to be hlfir.declare operation.
197-
void genUnpackArray(fir::FirOpBuilder &builder, mlir::Location loc,
198-
fir::FortranVariableOpInterface def,
197+
void genUnpackArray(Fortran::lower::AbstractConverter &converter,
198+
mlir::Location loc, fir::FortranVariableOpInterface def,
199199
const Fortran::semantics::Symbol &sym);
200200

201201
} // namespace lower

flang/include/flang/Optimizer/Dialect/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ set(LLVM_TARGET_DEFINITIONS FirAliasTagOpInterface.td)
2929
mlir_tablegen(FirAliasTagOpInterface.h.inc -gen-op-interface-decls)
3030
mlir_tablegen(FirAliasTagOpInterface.cpp.inc -gen-op-interface-defs)
3131

32+
set(LLVM_TARGET_DEFINITIONS SafeTempArrayCopyAttrInterface.td)
33+
mlir_tablegen(SafeTempArrayCopyAttrInterface.h.inc -gen-attr-interface-decls)
34+
mlir_tablegen(SafeTempArrayCopyAttrInterface.cpp.inc -gen-attr-interface-defs)
35+
add_public_tablegen_target(FIRSafeTempArrayCopyAttrInterfaceIncGen)
36+
3237
set(LLVM_TARGET_DEFINITIONS CanonicalizationPatterns.td)
3338
mlir_tablegen(CanonicalizationPatterns.inc -gen-rewriters)
3439
add_public_tablegen_target(CanonicalizationPatternsIncGen)

flang/include/flang/Optimizer/Dialect/FIRAttr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,6 @@ void printFirAttribute(FIROpsDialect *dialect, mlir::Attribute attr,
164164
#define GET_ATTRDEF_CLASSES
165165
#include "flang/Optimizer/Dialect/FIRAttr.h.inc"
166166

167+
#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h"
168+
167169
#endif // FORTRAN_OPTIMIZER_DIALECT_FIRATTR_H

flang/include/flang/Optimizer/Dialect/FIRAttr.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,4 +178,26 @@ def fir_PackArrayHeuristicsAttr
178178
let assemblyFormat = "`<` $value `>`";
179179
}
180180

181+
def fir_OpenACCSafeTempArrayCopyAttr : fir_Attr<"OpenACCSafeTempArrayCopy"> {
182+
let mnemonic = "acc_safe_temp_array_copy";
183+
let description = [{
184+
An attribute implementing SafeTempArrayCopyAttrInterface.
185+
It specifies whether it is possible to dynamically check
186+
if creating a temporary copy of a Fortran array is safe
187+
in the context of OpenACC.
188+
It also provides the methods to generate those dynamic checks.
189+
}];
190+
}
191+
192+
def fir_OpenMPSafeTempArrayCopyAttr : fir_Attr<"OpenMPSafeTempArrayCopy"> {
193+
let mnemonic = "omp_safe_temp_array_copy";
194+
let description = [{
195+
An attribute implementing SafeTempArrayCopyAttrInterface.
196+
It specifies whether it is possible to dynamically check
197+
if creating a temporary copy of a Fortran array is safe
198+
in the context of OpenMP.
199+
It also provides the methods to generate those dynamic checks.
200+
}];
201+
}
202+
181203
#endif // FIR_DIALECT_FIR_ATTRS

flang/include/flang/Optimizer/Dialect/FIRDialect.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ void addFIRInlinerExtension(mlir::DialectRegistry &registry);
4444
// Register implementation of LLVMTranslationDialectInterface.
4545
void addFIRToLLVMIRExtension(mlir::DialectRegistry &registry);
4646

47+
void registerFortranTempArrayCopyIsSafeExternalModels(
48+
mlir::DialectRegistry &registry);
49+
4750
} // namespace fir
4851

4952
#endif // FORTRAN_OPTIMIZER_DIALECT_FIRDIALECT_H

flang/include/flang/Optimizer/Dialect/FIROps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "flang/Optimizer/Dialect/FIRType.h"
1515
#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
1616
#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
17+
#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h"
1718
#include "mlir/Dialect/Arith/IR/Arith.h"
1819
#include "mlir/Dialect/Func/IR/FuncOps.h"
1920
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ include "flang/Optimizer/Dialect/FIRTypes.td"
2323
include "flang/Optimizer/Dialect/FIRAttr.td"
2424
include "flang/Optimizer/Dialect/FortranVariableInterface.td"
2525
include "flang/Optimizer/Dialect/FirAliasTagOpInterface.td"
26+
include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.td"
2627
include "mlir/IR/BuiltinAttributes.td"
2728

2829
// Base class for FIR operations.
@@ -3378,6 +3379,14 @@ def fir_PackArrayOp
33783379
that is eligible for repacking.
33793380
- heuristics attribute specifies conditions when the array repacking
33803381
may be optimized.
3382+
- is_safe is an optional non-empty array of SafeTempArrayCopyAttr
3383+
attributes. Each attribute implements SafeTempArrayCopyAttrInterface
3384+
that is used to generate a dynamic predicate value identifying
3385+
whether the creation of the temporary array copy is safe.
3386+
For example, if omp.fortran_safe_temp_array_copy attribute
3387+
is attached, its implementation may generate special code
3388+
to check if fir.pack_array may be executed by multiple
3389+
threads, and disallow repacking in this case.
33813390
}];
33823391

33833392
let arguments = (ins AnyBoxedArray:$array, UnitAttr:$stack,
@@ -3386,7 +3395,8 @@ def fir_PackArrayOp
33863395
OptionalAttr<UI64Attr>:$min_stride,
33873396
DefaultValuedAttr<fir_PackArrayHeuristicsAttr,
33883397
"::fir::PackArrayHeuristics::None">:$heuristics,
3389-
Variadic<AnyIntegerType>:$typeparams);
3398+
Variadic<AnyIntegerType>:$typeparams,
3399+
OptionalAttr<NonEmptySafeTempArrayCopyArrayAttr>:$is_safe);
33903400

33913401
let results = (outs AnyBoxedArray:$result);
33923402
let assemblyFormat = [{
@@ -3395,7 +3405,7 @@ def fir_PackArrayOp
33953405
(`no_copy` $no_copy^)?
33963406
(`constraints` custom<PackArrayConstraints>($max_size, $max_element_size, $min_stride)^)?
33973407
(`heuristics` $heuristics^)?
3398-
(`typeparams` $typeparams^)?
3408+
(`typeparams` $typeparams^)? (`is_safe` $is_safe^)?
33993409
attr-dict `:` functional-type(operands, results)
34003410
}];
34013411

@@ -3420,15 +3430,26 @@ def fir_UnpackArrayOp
34203430
was allocated.
34213431
- no_copy attribute indicates that the temporary array
34223432
is not copied into the original temporary array.
3433+
- is_safe is an optional non-empty array of SafeTempArrayCopyAttr
3434+
attributes. Each attribute implements SafeTempArrayCopyAttrInterface
3435+
that is used to generate extra code before any copy-out or
3436+
deallocation of the temporary happens.
3437+
For example, if acc.fortran_safe_temp_array_copy attribute
3438+
is attached, its implementation may generate special code
3439+
to check if the temporary has been transferred to OpenACC device
3440+
data environment, and issue a runtime error that the temporary
3441+
is present on the device while it is about to be deallocated
3442+
on the host.
34233443
}];
34243444

34253445
let arguments = (ins AnyBoxedArray:$temp, AnyBoxedArray:$original,
3426-
UnitAttr:$stack, UnitAttr:$no_copy);
3446+
UnitAttr:$stack, UnitAttr:$no_copy,
3447+
OptionalAttr<NonEmptySafeTempArrayCopyArrayAttr>:$is_safe);
34273448

34283449
let assemblyFormat = [{
34293450
$temp `to` $original
34303451
(`stack` $stack^):(`heap`)?
3431-
(`no_copy` $no_copy^)?
3452+
(`no_copy` $no_copy^)? (`is_safe` $is_safe^)?
34323453
attr-dict `:` type($original)
34333454
}];
34343455

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===- SafeTempArrayCopyAttrInterface.h -------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
//
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef FORTRAN_OPTIMIZER_DIALECT_SAFETEMPARRAYCOPYATTRINTERFACE_H
14+
#define FORTRAN_OPTIMIZER_DIALECT_SAFETEMPARRAYCOPYATTRINTERFACE_H
15+
16+
#include "flang/Optimizer/Dialect/FIRAttr.h"
17+
#include "flang/Optimizer/Dialect/FIRType.h"
18+
#include "mlir/IR/BuiltinTypes.h"
19+
#include "mlir/IR/OpDefinition.h"
20+
21+
namespace fir {
22+
class FirOpBuilder;
23+
}
24+
25+
#include "flang/Optimizer/Dialect/SafeTempArrayCopyAttrInterface.h.inc"
26+
27+
#endif // FORTRAN_OPTIMIZER_DIALECT_SAFETEMPARRAYCOPYATTRINTERFACE_H
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===- SafeTempArrayCopyAttrInterface.td -------------------*- tablegen -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
/// This file defines SafeTempArrayCopyAttrInterface and a generic attribute
10+
/// SafeTempArrayCopyAttr promising the SafeTempArrayCopyAttrInterface.
11+
///
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef FORTRAN_SAFETEMPARRAYCOPYATTRINTERFACE_TD
15+
#define FORTRAN_SAFETEMPARRAYCOPYATTRINTERFACE_TD
16+
17+
include "mlir/IR/OpBase.td"
18+
19+
def SafeTempArrayCopyAttrInterface
20+
: AttrInterface<"SafeTempArrayCopyAttrInterface"> {
21+
let cppNamespace = "::fir";
22+
let description = [{
23+
Interface for attributes defining whether creation of a temporary
24+
copy of a Fortran array is safe and/or how to produce proper
25+
dynamic checks to avoid it, if it is unsafe.
26+
}];
27+
28+
let methods =
29+
[StaticInterfaceMethod<
30+
/*desc=*/[{
31+
Returns true iff the usage of the temporary array copy
32+
can be made safe applying some dynamic checks.
33+
}],
34+
/*retTy=*/"bool",
35+
/*methodName=*/"isDynamicallySafe",
36+
/*args=*/(ins)>,
37+
StaticInterfaceMethod<
38+
/*desc=*/[{
39+
Generate FIR that produces an i1 Value indicating
40+
whether the creation of the temporary array copy is safe.
41+
\p array is a definition of the original array.
42+
The implementation may assume that \p array is present
43+
(though, it may be empty).
44+
}],
45+
/*retTy=*/"mlir::Value",
46+
/*methodName=*/"genDynamicCheck",
47+
/*args=*/
48+
(ins "::mlir::Location":$loc, "::fir::FirOpBuilder &":$builder,
49+
"::mlir::Value":$array)>,
50+
StaticInterfaceMethod<
51+
/*desc=*/[{
52+
This method allows inserting any FIR right before the optional
53+
copy-out (from \p temp to \p array) and the deallocation
54+
of the temporary array (implying that the temporary copy was
55+
actually created).
56+
}],
57+
/*retTy=*/"void",
58+
/*methodName=*/"registerTempDeallocation",
59+
/*args=*/
60+
(ins "::mlir::Location":$loc, "::fir::FirOpBuilder &":$builder,
61+
"::mlir::Value":$array, "::mlir::Value":$temp)>,
62+
];
63+
}
64+
65+
def SafeTempArrayCopyAttr
66+
: ConfinedAttr<
67+
AnyAttr, [PromisedAttrInterface<SafeTempArrayCopyAttrInterface>]> {
68+
let description = [{
69+
Generic attribute implementing or promising
70+
the `SafeTempArrayCopyAttrInterface` interface.
71+
}];
72+
}
73+
74+
def SafeTempArrayCopyArrayAttr
75+
: TypedArrayAttrBase<SafeTempArrayCopyAttr,
76+
"array of SafeTempArrayCopyAttr attributes">;
77+
78+
def NonEmptySafeTempArrayCopyArrayAttr
79+
: ConfinedAttr<SafeTempArrayCopyArrayAttr, [ArrayMinCount<1>]>;
80+
81+
#endif // FORTRAN_SAFETEMPARRAYCOPYATTRINTERFACE_TD

flang/include/flang/Optimizer/OpenACC/RegisterOpenACCExtensions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ namespace fir::acc {
1717

1818
void registerOpenACCExtensions(mlir::DialectRegistry &registry);
1919

20+
/// Register external models for FIR attributes related to OpenACC.
21+
void registerAttrsExtensions(mlir::DialectRegistry &registry);
22+
23+
/// Register all dialects whose operations may be created
24+
/// by the transformational attributes.
25+
void registerTransformationalAttrsDependentDialects(
26+
mlir::DialectRegistry &registry);
27+
2028
} // namespace fir::acc
2129

2230
#endif // FLANG_OPTIMIZER_OPENACC_REGISTEROPENACCEXTENSIONS_H_
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===- RegisterOpenMPExtensions.h - OpenMP Extension Registration -*- C++ -*-=//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef FLANG_OPTIMIZER_OPENMP_SUPPORT_REGISTEROPENMPEXTENSIONS_H_
10+
#define FLANG_OPTIMIZER_OPENMP_SUPPORT_REGISTEROPENMPEXTENSIONS_H_
11+
12+
namespace mlir {
13+
class DialectRegistry;
14+
} // namespace mlir
15+
16+
namespace fir::omp {
17+
18+
void registerOpenMPExtensions(mlir::DialectRegistry &registry);
19+
20+
/// Register external models for FIR attributes related to OpenMP.
21+
void registerAttrsExtensions(mlir::DialectRegistry &registry);
22+
23+
/// Register all dialects whose operations may be created
24+
/// by the transformational attributes.
25+
void registerTransformationalAttrsDependentDialects(
26+
mlir::DialectRegistry &registry);
27+
28+
} // namespace fir::omp
29+
30+
#endif // FLANG_OPTIMIZER_OPENMP_SUPPORT_REGISTEROPENMPEXTENSIONS_H_

0 commit comments

Comments
 (0)