[Mlir-commits] [mlir] [mlir][acc] Introduce MappableType interface (PR #122146)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jan 8 09:41:30 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-openacc
Author: Razvan Lupusoru (razvanlupusoru)
<details>
<summary>Changes</summary>
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.
---
Patch is 72.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/122146.diff
6 Files Affected:
- (modified) mlir/docs/Dialects/OpenACCDialect.md (+83-15)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACC.h (+36-8)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+172-112)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td (+93)
- (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+206-14)
- (modified) mlir/unittests/Dialect/OpenACC/OpenACCOpsTest.cpp (+106-22)
``````````diff
diff --git a/mlir/docs/Dialects/OpenACCDialect.md b/mlir/docs/Dialects/OpenACCDialect.md
index 2f1bb194a167d4..39218a9676ff34 100755
--- a/mlir/docs/Dialects/OpenACCDialect.md
+++ b/mlir/docs/Dialects/OpenACCDialect.md
@@ -274,28 +274,96 @@ reference counters are zero, a delete action is performed.
### Types
-There are a few acc dialect type categories to describe:
-* type of acc data clause operation input `varPtr`
- - The type of `varPtr` must be pointer-like. This is done by
- attaching the `PointerLikeType` interface to the appropriate MLIR
- type. Although memory/storage concept is a lower level abstraction,
- it is useful because the OpenACC model distinguishes between host
- and device memory explicitly - and the mapping between the two is
- done through pointers. Thus, by explicitly requiring it in the
- dialect, the appropriate language frontend must create storage or
- use type that satisfies the mapping constraint.
+Since the `acc dialect` is meant to be used alongside other dialects which
+represent the source language, appropriate use of types and type interfaces is
+key to ensuring compatibility. This section describes those considerations.
+
+#### Data Clause Operation Types
+
+Data clause operations (eg. `acc.copyin`) rely on the following type
+considerations:
+* type of acc data clause operation input `var`
+ - The type of `var` must be one with `PointerLikeType` or `MappableType`
+ interfaces attached. The first, `PointerLikeType`, is useful because
+ the OpenACC memory model distinguishes between host and device memory
+ explicitly - and the mapping between the two is done through pointers. Thus,
+ by explicitly requiring it in the dialect, the appropriate language
+ frontend must create storage or use type that satisfies the mapping
+ constraint. The second possibility, `MappableType` was added because
+ memory/storage concept is a lower level abstraction and not all dialects
+ choose to use a pointer abstraction especially in the case where semantics
+ are more complex (such as `fir.box` which represents Fortran descriptors
+ and is defined in the `fir` dialect used from `flang`).
* type of result of acc data clause operations
- The type of the acc data clause operation is exactly the same as
- `varPtr`. This was done intentionally instead of introducing an
- `acc.ref/ptr` type so that IR compatibility and the dialect's
+ `var`. This was done intentionally instead of introducing specific `acc`
+ output types so that so that IR compatibility and the dialect's
existing strong type checking can be maintained. This is needed
since the `acc` dialect must live within another dialect whose type
- system is unknown to it. The only constraint is that the appropriate
- dialect type must use the `PointerLikeType` interface.
+ system is unknown to it.
+* variable type captured in `varType`
+ - When `var`'s type is `PointerLikeType`, the actual type of the target
+ may be lost. More specifically, dialects like `llvm` which use opaque
+ pointers, do not record the target variable's type. The use of this field
+ bridges this gap.
* type of decomposed clauses
- Decomposed clauses, such as `acc.bounds` and `acc.declare_enter`
produce types to allow their results to be used only in specific
- operations.
+ operations. These are synthetic types solely used for proper IR
+ construction.
+
+#### Pointer-Like Requirement
+
+The need to have pointer-type requirement in the acc dialect stems from
+a few different aspects:
+- Existing dialects like `hlfir`, `fir`, `cir`, `llvm` use a pointer
+representation for variables.
+- Reference counters (for data clauses) are described in terms of
+memory. In OpenACC spec 3.3 in section 2.6.7. It says: "A structured reference
+counter is incremented when entering each data or compute region that contain an
+explicit data clause or implicitly-determined data attributes for that section
+of memory". This implies addressability of memory.
+- Attach semantics (2.6.8 attachment counter) are specified using
+"address" terminology: "The attachment counter for a pointer is set to
+one whenever the pointer is attached to new target address, and
+incremented whenever an attach action for that pointer is performed for
+the same target address.
+
+#### Type Interfaces
+
+The `acc` dialect describes two different type interfaces which must be
+implemented and attached to the source dialect's types in order to allow use
+of data clause operations (eg. `acc.copyin`). They are as follows:
+* `PointerLikeType`
+ - The idea behind this interface is that variables end up being represented
+ as pointers in many dialects. More specifically, `fir`, `cir`, `llvm`
+ represent user declared local variables with some dialect specific form of
+ `alloca` operation which produce pointers. Globals, similarly, are referred by
+ their address through some form of `address_of` operation. Additionally, an
+ implementation for OpenACC runtime needs to distinguish between device and
+ host memory - also typically done by talking about pointers. So this type
+ interface requirement fits in naturally with OpenACC specification. Data
+ mapping operation semantics can often be simply described by a pointer and
+ size of the data it points to.
+* `MappableType`
+ - This interface was introduced because the `PointerLikeType` requirement
+ cannot represent cases when the source dialect does not use pointers. Also,
+ some cases, such as Fortran descriptor-backed arrays and Fortran optional
+ arguments, require decomposition into multiple steps. For example, in the
+ descriptor case, mapping of descriptor is needed, mapping of the data, and
+ implicit attach into device descriptor. In order to allow capturing all of
+ this complexity with a single data clause operation, the `MappableType`
+ interface was introduced. This is consistent with the dialect's goals
+ including being "able to regenerate the semantic equivalent of the user
+ pragmas".
+
+The intent is that a dialect's type system implements one of these two
+interfaces. And to be precise, a type should only implement one or the other
+(and not both) - since keeping them separate avoids ambiguity on what actually
+needs mapped. When `var` is `PointerLikeType`, the assumption is that the data
+pointed-to will be mapped. If the pointer-like type also implemented
+`MappableType` interface, it becomes ambiguous whether the data pointed to or
+the pointer itself is being mapped.
### Recipes
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index cda07d6a913649..748cb7f28fc8c4 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -25,6 +25,7 @@
#include "mlir/Dialect/OpenACC/OpenACCOpsInterfaces.h.inc"
#include "mlir/Dialect/OpenACC/OpenACCTypeInterfaces.h.inc"
#include "mlir/Dialect/OpenACCMPCommon/Interfaces/AtomicInterfaces.h"
+#include "mlir/IR/Value.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/LoopLikeInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
@@ -83,16 +84,31 @@ namespace acc {
/// combined and the final mapping value would be 5 (4 | 1).
enum OpenACCExecMapping { NONE = 0, VECTOR = 1, WORKER = 2, GANG = 4 };
-/// Used to obtain the `varPtr` from a data clause operation.
+/// Used to obtain the `var` from a data clause operation.
/// Returns empty value if not a data clause operation or is a data exit
-/// operation with no `varPtr`.
-mlir::Value getVarPtr(mlir::Operation *accDataClauseOp);
-
-/// Used to obtain the `accPtr` from a data clause operation.
-/// When a data entry operation, it obtains its result `accPtr` value.
-/// If a data exit operation, it obtains its operand `accPtr` value.
+/// operation with no `var`.
+mlir::Value getVar(mlir::Operation *accDataClauseOp);
+
+/// Used to obtain the `var` from a data clause operation if it implements
+/// `PointerLikeType`.
+mlir::TypedValue<mlir::acc::PointerLikeType>
+getVarPtr(mlir::Operation *accDataClauseOp);
+
+/// Used to obtains the `varType` from a data clause operation which records
+/// the type of variable. When `var` is `PointerLikeType`, this returns
+/// the type of the pointer target.
+mlir::Type getVarType(mlir::Operation *accDataClauseOp);
+
+/// Used to obtain the `accVar` from a data clause operation.
+/// When a data entry operation, it obtains its result `accVar` value.
+/// If a data exit operation, it obtains its operand `accVar` value.
/// Returns empty value if not a data clause operation.
-mlir::Value getAccPtr(mlir::Operation *accDataClauseOp);
+mlir::Value getAccVar(mlir::Operation *accDataClauseOp);
+
+/// Used to obtain the `accVar` from a data clause operation if it implements
+/// `PointerLikeType`.
+mlir::TypedValue<mlir::acc::PointerLikeType>
+getAccPtr(mlir::Operation *accDataClauseOp);
/// Used to obtain the `varPtrPtr` from a data clause operation.
/// Returns empty value if not a data clause operation.
@@ -136,6 +152,18 @@ mlir::ValueRange getDataOperands(mlir::Operation *accOp);
/// Used to get a mutable range iterating over the data operands.
mlir::MutableOperandRange getMutableDataOperands(mlir::Operation *accOp);
+/// Used to check whether the provided `type` implements the `PointerLikeType`
+/// interface.
+inline bool isPointerLikeType(mlir::Type type) {
+ return mlir::isa<mlir::acc::PointerLikeType>(type);
+}
+
+/// Used to check whether the provided `type` implements the `MappableType`
+/// interface.
+inline bool isMappableType(mlir::Type type) {
+ return mlir::isa<mlir::acc::MappableType>(type);
+}
+
/// Used to obtain the attribute name for declare.
static constexpr StringLiteral getDeclareAttrName() {
return StringLiteral("acc.declare");
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 3ac265ac687561..a47f70b168066e 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -70,7 +70,14 @@ def IntOrIndex : AnyTypeOf<[AnyInteger, Index]>;
// Simple alias to pointer-like interface to reduce verbosity.
def OpenACC_PointerLikeType : TypeAlias<OpenACC_PointerLikeTypeInterface,
- "pointer-like type">;
+ "pointer-like type">;
+def OpenACC_MappableType : TypeAlias<OpenACC_MappableTypeInterface,
+ "mappable type">;
+
+def OpenACC_AnyPointerOrMappableLike : TypeConstraint<Or<[OpenACC_PointerLikeType.predicate,
+ OpenACC_MappableType.predicate]>, "any pointer or mappable">;
+def OpenACC_AnyPointerOrMappableType : Type<OpenACC_AnyPointerOrMappableLike.predicate,
+ "any pointer or mappable">;
// Define the OpenACC data clauses. There are a few cases where a modifier
// is used, like create(zero), copyin(readonly), and copyout(zero). Since in
@@ -353,7 +360,8 @@ def OpenACC_DataBoundsOp : OpenACC_Op<"bounds",
build($_builder, $_state,
::mlir::acc::DataBoundsType::get($_builder.getContext()),
/*lowerbound=*/{}, /*upperbound=*/{}, extent,
- /*stride=*/{}, /*strideInBytes=*/nullptr, /*startIdx=*/{});
+ /*stride=*/{}, /*strideInBytes=*/$_builder.getBoolAttr(false),
+ /*startIdx=*/{});
}]
>,
OpBuilder<(ins "::mlir::Value":$lowerbound,
@@ -361,7 +369,8 @@ def OpenACC_DataBoundsOp : OpenACC_Op<"bounds",
build($_builder, $_state,
::mlir::acc::DataBoundsType::get($_builder.getContext()),
lowerbound, upperbound, /*extent=*/{},
- /*stride=*/{}, /*strideInBytes=*/nullptr, /*startIdx=*/{});
+ /*stride=*/{}, /*strideInBytes=*/$_builder.getBoolAttr(false),
+ /*startIdx=*/{});
}]
>
];
@@ -396,10 +405,15 @@ class OpenACC_DataEntryOp<string mnemonic, string clause, string extraDescriptio
let description = !strconcat(extraDescription, [{
Description of arguments:
- - `varPtr`: The address of variable to copy.
- - `varPtrPtr`: Specifies the address of varPtr - only used when the variable
- copied is a field in a struct. This is important for OpenACC due to implicit
- attach semantics on data clauses (2.6.4).
+ - `var`: The variable to copy. Must be either `MappableType` or
+ `PointerLikeType`.
+ - `varType`: The type of the variable that is being copied. When `var` is
+ a `MappableType`, this matches the type of `var`. When `var` is a
+ `PointerLikeType`, this type holds information about the target of the
+ pointer.
+ - `varPtrPtr`: Specifies the address of the address of `var` - only used
+ when the variable copied is a field in a struct. This is important for
+ OpenACC due to implicit attach semantics on data clauses (2.6.4).
- `bounds`: Used when copying just slice of array or array's bounds are not
encoded in type. They are in rank order where rank 0 is inner-most dimension.
- `asyncOperands` and `asyncOperandsDeviceType`:
@@ -456,42 +470,74 @@ class OpenACC_DataEntryOp<string mnemonic, string clause, string extraDescriptio
}
return nullptr;
}
+ mlir::TypedValue<mlir::acc::PointerLikeType> getVarPtr() {
+ return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getVar());
+ }
+ mlir::TypedValue<mlir::acc::PointerLikeType> getAccPtr() {
+ return mlir::dyn_cast<mlir::TypedValue<mlir::acc::PointerLikeType>>(getAccVar());
+ }
}];
let assemblyFormat = [{
- `varPtr` `(` $varPtr `:` custom<VarPtrType>(type($varPtr), $varType)
+ custom<Var>($var) `:` custom<VarPtrType>(type($var), $varType)
oilist(
`varPtrPtr` `(` $varPtrPtr `:` type($varPtrPtr) `)`
| `bounds` `(` $bounds `)`
| `async` `(` custom<DeviceTypeOperands>($asyncOperands,
type($asyncOperands), $asyncOperandsDeviceType) `)`
- ) `->` type($accPtr) attr-dict
+ ) `->` type($accVar) attr-dict
}];
let hasVerifier = 1;
- let builders = [OpBuilder<(ins "::mlir::Value":$varPtr, "bool":$structured,
- "bool":$implicit,
- CArg<"::mlir::ValueRange", "{}">:$bounds),
- [{
+ let builders = [
+ OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr,
+ "bool":$structured, "bool":$implicit,
+ CArg<"::mlir::ValueRange", "{}">:$bounds),
+ [{
build($_builder, $_state, varPtr.getType(), varPtr,
/*varType=*/::mlir::TypeAttr::get(
- ::mlir::cast<::mlir::acc::PointerLikeType>(
- varPtr.getType()).getElementType()),
+ varPtr.getType().getElementType()),
/*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
/*asyncOperandsDeviceType=*/nullptr,
/*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
/*structured=*/$_builder.getBoolAttr(structured),
/*implicit=*/$_builder.getBoolAttr(implicit), /*name=*/nullptr);
}]>,
- OpBuilder<(ins "::mlir::Value":$varPtr, "bool":$structured,
- "bool":$implicit, "const ::llvm::Twine &":$name,
- CArg<"::mlir::ValueRange", "{}">:$bounds),
- [{
+ OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$varPtr,
+ "bool":$structured, "bool":$implicit,
+ "const ::llvm::Twine &":$name,
+ CArg<"::mlir::ValueRange", "{}">:$bounds),
+ [{
build($_builder, $_state, varPtr.getType(), varPtr,
/*varType=*/::mlir::TypeAttr::get(
- ::mlir::cast<::mlir::acc::PointerLikeType>(
- varPtr.getType()).getElementType()),
+ varPtr.getType().getElementType()),
+ /*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
+ /*asyncOperandsDeviceType=*/nullptr,
+ /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
+ /*structured=*/$_builder.getBoolAttr(structured),
+ /*implicit=*/$_builder.getBoolAttr(implicit),
+ /*name=*/$_builder.getStringAttr(name));
+ }]>,
+ OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var,
+ "bool":$structured, "bool":$implicit,
+ CArg<"::mlir::ValueRange", "{}">:$bounds),
+ [{
+ build($_builder, $_state, var.getType(), var,
+ /*varType=*/::mlir::TypeAttr::get(var.getType()),
+ /*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
+ /*asyncOperandsDeviceType=*/nullptr,
+ /*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
+ /*structured=*/$_builder.getBoolAttr(structured),
+ /*implicit=*/$_builder.getBoolAttr(implicit), /*name=*/nullptr);
+ }]>,
+ OpBuilder<(ins "::mlir::TypedValue<::mlir::acc::MappableType>":$var,
+ "bool":$structured, "bool":$implicit,
+ "const ::llvm::Twine &":$name,
+ CArg<"::mlir::ValueRange", "{}">:$bounds),
+ [{
+ build($_builder, $_state, var.getType(), var,
+ /*varType=*/::mlir::TypeAttr::get(var.getType()),
/*varPtrPtr=*/{}, bounds, /*asyncOperands=*/{},
/*asyncOperandsDeviceType=*/nullptr,
/*asyncOnly=*/nullptr, /*dataClause=*/nullptr,
@@ -506,10 +552,10 @@ class OpenACC_DataEntryOp<string mnemonic, string clause, string extraDescriptio
//===----------------------------------------------------------------------===//
def OpenACC_PrivateOp : OpenACC_DataEntryOp<"private",
"mlir::acc::DataClause::acc_private", "", [],
- (ins OpenACC_PointerLikeTypeInterface:$varPtr)> {
+ (ins OpenACC_AnyPointerOrMappableType:$var)> {
let summary = "Represents private semantics for acc private clause.";
- let results = (outs Arg<OpenACC_PointerLikeTypeInterface,
- "Address of device variable",[MemWrite]>:$accPtr);
+ let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
+ "Accelerator mapped variable",[MemWrite]>:$accVar);
let extraClassDeclaration = extraClassDeclarationBase;
}
@@ -518,11 +564,11 @@ def OpenACC_PrivateOp : OpenACC_DataEntryOp<"private",
//===----------------------------------------------------------------------===//
def OpenACC_FirstprivateOp : OpenACC_DataEntryOp<"firstprivate",
"mlir::acc::DataClause::acc_firstprivate", "", [],
- (ins Arg<OpenACC_PointerLikeTypeInterface,"Address of variable",[MemRead]>:$varPtr)> {
+ (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
let summary = "Represents firstprivate semantic for the acc firstprivate "
"clause.";
- let results = (outs Arg<OpenACC_PointerLikeTypeInterface,
- "Address of device variable",[MemWrite]>:$accPtr);
+ let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
+ "Accelerator mapped variable",[MemWrite]>:$accVar);
let extraClassDeclaration = extraClassDeclarationBase;
}
@@ -531,10 +577,10 @@ def OpenACC_FirstprivateOp : OpenACC_DataEntryOp<"firstprivate",
//===----------------------------------------------------------------------===//
def OpenACC_ReductionOp : OpenACC_DataEntryOp<"reduction",
"mlir::acc::DataClause::acc_reduction", "", [],
- (ins Arg<OpenACC_PointerLikeTypeInterface,"Address of variable",[MemRead]>:$varPtr)> {
+ (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
let summary = "Represents reduction semantics for acc reduction clause.";
- let results = (outs Arg<OpenACC_PointerLikeTypeInterface,
- "Address of device variable",[MemWrite]>:$accPtr);
+ let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
+ "Accelerator mapped variable",[MemWrite]>:$accVar);
let extraClassDeclaration = extraClassDeclarationBase;
}
@@ -544,9 +590,9 @@ def OpenACC_ReductionOp : OpenACC_DataEntryOp<"reduction",
def OpenACC_DevicePtrOp : OpenACC_DataEntryOp<"deviceptr",
"mlir::acc::DataClause::acc_deviceptr", "",
[MemoryEffects<[MemRead<OpenACC_RuntimeCounters>]>],
- (ins OpenACC_PointerLikeTypeInterface:$varPtr)> {
+ (ins OpenACC_AnyPointerOrMappableType:$var)> {
let summary = "Specifies that the variable pointer is a device pointer.";
- let results = (outs OpenACC_PointerLikeTypeInterface:$accPtr);
+ let results = (outs OpenACC_AnyPointerOrMappableType:$ac...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/122146
More information about the Mlir-commits
mailing list