Skip to content

Commit cbcb7ad

Browse files
[mlir][acc] Introduce MappableType interface (#122146)
OpenACC data clause operations previously required that the variable operand implemented PointerLikeType interface. This was a reasonable constraint because the dialects currently mixed with `acc` do use pointers to represent variables. However, this forces the "pointer" abstraction to be exposed too early and some cases are not cleanly representable through this approach (more specifically FIR's `fix.box` abstraction). Thus, relax this by allowing a variable to be a type which implements either `PointerLikeType` interface or `MappableType` interface.
1 parent 6beaa45 commit cbcb7ad

File tree

6 files changed

+696
-171
lines changed

6 files changed

+696
-171
lines changed

mlir/docs/Dialects/OpenACCDialect.md

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -274,28 +274,96 @@ reference counters are zero, a delete action is performed.
274274

275275
### Types
276276

277-
There are a few acc dialect type categories to describe:
278-
* type of acc data clause operation input `varPtr`
279-
- The type of `varPtr` must be pointer-like. This is done by
280-
attaching the `PointerLikeType` interface to the appropriate MLIR
281-
type. Although memory/storage concept is a lower level abstraction,
282-
it is useful because the OpenACC model distinguishes between host
283-
and device memory explicitly - and the mapping between the two is
284-
done through pointers. Thus, by explicitly requiring it in the
285-
dialect, the appropriate language frontend must create storage or
286-
use type that satisfies the mapping constraint.
277+
Since the `acc dialect` is meant to be used alongside other dialects which
278+
represent the source language, appropriate use of types and type interfaces is
279+
key to ensuring compatibility. This section describes those considerations.
280+
281+
#### Data Clause Operation Types
282+
283+
Data clause operations (eg. `acc.copyin`) rely on the following type
284+
considerations:
285+
* type of acc data clause operation input `var`
286+
- The type of `var` must be one with `PointerLikeType` or `MappableType`
287+
interfaces attached. The first, `PointerLikeType`, is useful because
288+
the OpenACC memory model distinguishes between host and device memory
289+
explicitly - and the mapping between the two is done through pointers. Thus,
290+
by explicitly requiring it in the dialect, the appropriate language
291+
frontend must create storage or use type that satisfies the mapping
292+
constraint. The second possibility, `MappableType` was added because
293+
memory/storage concept is a lower level abstraction and not all dialects
294+
choose to use a pointer abstraction especially in the case where semantics
295+
are more complex (such as `fir.box` which represents Fortran descriptors
296+
and is defined in the `fir` dialect used from `flang`).
287297
* type of result of acc data clause operations
288298
- The type of the acc data clause operation is exactly the same as
289-
`varPtr`. This was done intentionally instead of introducing an
290-
`acc.ref/ptr` type so that IR compatibility and the dialect's
299+
`var`. This was done intentionally instead of introducing specific `acc`
300+
output types so that so that IR compatibility and the dialect's
291301
existing strong type checking can be maintained. This is needed
292302
since the `acc` dialect must live within another dialect whose type
293-
system is unknown to it. The only constraint is that the appropriate
294-
dialect type must use the `PointerLikeType` interface.
303+
system is unknown to it.
304+
* variable type captured in `varType`
305+
- When `var`'s type is `PointerLikeType`, the actual type of the target
306+
may be lost. More specifically, dialects like `llvm` which use opaque
307+
pointers, do not record the target variable's type. The use of this field
308+
bridges this gap.
295309
* type of decomposed clauses
296310
- Decomposed clauses, such as `acc.bounds` and `acc.declare_enter`
297311
produce types to allow their results to be used only in specific
298-
operations.
312+
operations. These are synthetic types solely used for proper IR
313+
construction.
314+
315+
#### Pointer-Like Requirement
316+
317+
The need to have pointer-type requirement in the acc dialect stems from
318+
a few different aspects:
319+
- Existing dialects like `hlfir`, `fir`, `cir`, `llvm` use a pointer
320+
representation for variables.
321+
- Reference counters (for data clauses) are described in terms of
322+
memory. In OpenACC spec 3.3 in section 2.6.7. It says: "A structured reference
323+
counter is incremented when entering each data or compute region that contain an
324+
explicit data clause or implicitly-determined data attributes for that section
325+
of memory". This implies addressability of memory.
326+
- Attach semantics (2.6.8 attachment counter) are specified using
327+
"address" terminology: "The attachment counter for a pointer is set to
328+
one whenever the pointer is attached to new target address, and
329+
incremented whenever an attach action for that pointer is performed for
330+
the same target address.
331+
332+
#### Type Interfaces
333+
334+
The `acc` dialect describes two different type interfaces which must be
335+
implemented and attached to the source dialect's types in order to allow use
336+
of data clause operations (eg. `acc.copyin`). They are as follows:
337+
* `PointerLikeType`
338+
- The idea behind this interface is that variables end up being represented
339+
as pointers in many dialects. More specifically, `fir`, `cir`, `llvm`
340+
represent user declared local variables with some dialect specific form of
341+
`alloca` operation which produce pointers. Globals, similarly, are referred by
342+
their address through some form of `address_of` operation. Additionally, an
343+
implementation for OpenACC runtime needs to distinguish between device and
344+
host memory - also typically done by talking about pointers. So this type
345+
interface requirement fits in naturally with OpenACC specification. Data
346+
mapping operation semantics can often be simply described by a pointer and
347+
size of the data it points to.
348+
* `MappableType`
349+
- This interface was introduced because the `PointerLikeType` requirement
350+
cannot represent cases when the source dialect does not use pointers. Also,
351+
some cases, such as Fortran descriptor-backed arrays and Fortran optional
352+
arguments, require decomposition into multiple steps. For example, in the
353+
descriptor case, mapping of descriptor is needed, mapping of the data, and
354+
implicit attach into device descriptor. In order to allow capturing all of
355+
this complexity with a single data clause operation, the `MappableType`
356+
interface was introduced. This is consistent with the dialect's goals
357+
including being "able to regenerate the semantic equivalent of the user
358+
pragmas".
359+
360+
The intent is that a dialect's type system implements one of these two
361+
interfaces. And to be precise, a type should only implement one or the other
362+
(and not both) - since keeping them separate avoids ambiguity on what actually
363+
needs mapped. When `var` is `PointerLikeType`, the assumption is that the data
364+
pointed-to will be mapped. If the pointer-like type also implemented
365+
`MappableType` interface, it becomes ambiguous whether the data pointed to or
366+
the pointer itself is being mapped.
299367

300368
### Recipes
301369

mlir/include/mlir/Dialect/OpenACC/OpenACC.h

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.h.inc"
2626
#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.h.inc"
2727
#include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.h"
28+
#include "mlir/IR/Value.h"
2829
#include "mlir/Interfaces/ControlFlowInterfaces.h"
2930
#include "mlir/Interfaces/LoopLikeInterface.h"
3031
#include "mlir/Interfaces/SideEffectInterfaces.h"
@@ -83,16 +84,31 @@ namespace acc {
8384
/// combined and the final mapping value would be 5 (4 | 1).
8485
enum OpenACCExecMapping { NONE = 0, VECTOR = 1, WORKER = 2, GANG = 4 };
8586

86-
/// Used to obtain the `varPtr` from a data clause operation.
87+
/// Used to obtain the `var` from a data clause operation.
8788
/// Returns empty value if not a data clause operation or is a data exit
88-
/// operation with no `varPtr`.
89-
mlir::Value getVarPtr(mlir::Operation *accDataClauseOp);
90-
91-
/// Used to obtain the `accPtr` from a data clause operation.
92-
/// When a data entry operation, it obtains its result `accPtr` value.
93-
/// If a data exit operation, it obtains its operand `accPtr` value.
89+
/// operation with no `var`.
90+
mlir::Value getVar(mlir::Operation *accDataClauseOp);
91+
92+
/// Used to obtain the `var` from a data clause operation if it implements
93+
/// `PointerLikeType`.
94+
mlir::TypedValue<mlir::acc::PointerLikeType>
95+
getVarPtr(mlir::Operation *accDataClauseOp);
96+
97+
/// Used to obtains the `varType` from a data clause operation which records
98+
/// the type of variable. When `var` is `PointerLikeType`, this returns
99+
/// the type of the pointer target.
100+
mlir::Type getVarType(mlir::Operation *accDataClauseOp);
101+
102+
/// Used to obtain the `accVar` from a data clause operation.
103+
/// When a data entry operation, it obtains its result `accVar` value.
104+
/// If a data exit operation, it obtains its operand `accVar` value.
94105
/// Returns empty value if not a data clause operation.
95-
mlir::Value getAccPtr(mlir::Operation *accDataClauseOp);
106+
mlir::Value getAccVar(mlir::Operation *accDataClauseOp);
107+
108+
/// Used to obtain the `accVar` from a data clause operation if it implements
109+
/// `PointerLikeType`.
110+
mlir::TypedValue<mlir::acc::PointerLikeType>
111+
getAccPtr(mlir::Operation *accDataClauseOp);
96112

97113
/// Used to obtain the `varPtrPtr` from a data clause operation.
98114
/// Returns empty value if not a data clause operation.
@@ -136,6 +152,18 @@ mlir::ValueRange getDataOperands(mlir::Operation *accOp);
136152
/// Used to get a mutable range iterating over the data operands.
137153
mlir::MutableOperandRange getMutableDataOperands(mlir::Operation *accOp);
138154

155+
/// Used to check whether the provided `type` implements the `PointerLikeType`
156+
/// interface.
157+
inline bool isPointerLikeType(mlir::Type type) {
158+
return mlir::isa<mlir::acc::PointerLikeType>(type);
159+
}
160+
161+
/// Used to check whether the provided `type` implements the `MappableType`
162+
/// interface.
163+
inline bool isMappableType(mlir::Type type) {
164+
return mlir::isa<mlir::acc::MappableType>(type);
165+
}
166+
139167
/// Used to obtain the attribute name for declare.
140168
static constexpr StringLiteral getDeclareAttrName() {
141169
return StringLiteral("acc.declare");

0 commit comments

Comments
 (0)