mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 03:56:16 +08:00
[openacc] Add attribute to hold declare data clause information
For variables in declare clauses, their producing operation should be marked with the data clause for ease of lookup and consistency verification. Thus add an attribute that can be used for this purpose plus verification that declare data operation matches the declare data clause on variable. Reviewed By: clementval Differential Revision: https://reviews.llvm.org/D155640
This commit is contained in:
@@ -34,6 +34,22 @@
|
||||
#define GET_OP_CLASSES
|
||||
#include "mlir/Dialect/OpenACC/OpenACCOps.h.inc"
|
||||
|
||||
#define ACC_DATA_ENTRY_OPS \
|
||||
mlir::acc::CopyinOp, mlir::acc::CreateOp, mlir::acc::PresentOp, \
|
||||
mlir::acc::NoCreateOp, mlir::acc::AttachOp, mlir::acc::DevicePtrOp, \
|
||||
mlir::acc::GetDevicePtrOp, mlir::acc::PrivateOp, \
|
||||
mlir::acc::FirstprivateOp, mlir::acc::UpdateDeviceOp, \
|
||||
mlir::acc::UseDeviceOp, mlir::acc::ReductionOp, \
|
||||
mlir::acc::DeclareDeviceResidentOp, mlir::acc::DeclareLinkOp
|
||||
#define ACC_COMPUTE_CONSTRUCT_OPS \
|
||||
mlir::acc::ParallelOp, mlir::acc::KernelsOp, mlir::acc::SerialOp
|
||||
#define ACC_DATA_CONSTRUCT_OPS \
|
||||
mlir::acc::DataOp, mlir::acc::EnterDataOp, mlir::acc::ExitDataOp, \
|
||||
mlir::acc::UpdateOp, mlir::acc::HostDataOp, \
|
||||
mlir::acc::DeclareEnterOp mlir::acc::DeclareExitOp
|
||||
#define ACC_COMPUTE_AND_DATA_CONSTRUCT_OPS \
|
||||
ACC_COMPUTE_CONSTRUCT_OPS, ACC_DATA_CONSTRUCT_OPS
|
||||
|
||||
namespace mlir {
|
||||
namespace acc {
|
||||
|
||||
@@ -48,6 +64,20 @@ 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 entry operation.
|
||||
/// Returns empty value if not a data entry operation.
|
||||
mlir::Value getVarPtr(mlir::Operation *accDataEntryOp);
|
||||
|
||||
/// Used to obtain the `dataClause` from a data entry operation.
|
||||
/// Returns empty optional if not a data entry operation.
|
||||
std::optional<mlir::acc::DataClause>
|
||||
getDataClause(mlir::Operation *accDataEntryOp);
|
||||
|
||||
/// Used to obtain the attribute name for declare.
|
||||
static constexpr StringLiteral getDeclareAttrName() {
|
||||
return StringLiteral("acc.declare");
|
||||
}
|
||||
|
||||
} // namespace acc
|
||||
} // namespace mlir
|
||||
|
||||
|
||||
@@ -116,6 +116,25 @@ def OpenACC_DataClauseEnum : I64EnumAttr<"DataClause",
|
||||
def OpenACC_DataClauseAttr : EnumAttr<OpenACC_Dialect, OpenACC_DataClauseEnum,
|
||||
"data_clause">;
|
||||
|
||||
class OpenACC_Attr<string name, string attrMnemonic,
|
||||
list<Trait> traits = [],
|
||||
string baseCppClass = "::mlir::Attribute">
|
||||
: AttrDef<OpenACC_Dialect, name, traits, baseCppClass> {
|
||||
let mnemonic = attrMnemonic;
|
||||
}
|
||||
|
||||
// Attribute to describe the declare data clause used on variable.
|
||||
// Intended to be used at the variable creation site (on the global op or the
|
||||
// corresponding allocation operation). This is used in conjunction with the
|
||||
// declare operations (`acc.declare_enter` and `acc.declare_exit`) since those
|
||||
// describe how the data action is performed. The attribute itself makes it
|
||||
// easier to find out whether the variable is in a declare clause and what kind
|
||||
// of clause it is.
|
||||
def DeclareAttr : OpenACC_Attr<"Declare", "declare"> {
|
||||
let parameters = (ins "DataClauseAttr":$dataClause);
|
||||
let assemblyFormat = "`<` struct(params) `>`";
|
||||
}
|
||||
|
||||
// Used for data specification in data clauses (2.7.1).
|
||||
// Either (or both) extent and upperbound must be specified.
|
||||
def OpenACC_DataBoundsOp : OpenACC_Op<"bounds",
|
||||
|
||||
@@ -987,7 +987,7 @@ static LogicalResult checkDeclareOperands(Op &op,
|
||||
op->getLoc(),
|
||||
"at least one operand must appear on the declare operation");
|
||||
|
||||
for (mlir::Value operand : operands)
|
||||
for (mlir::Value operand : operands) {
|
||||
if (!mlir::isa<acc::CopyinOp, acc::CopyoutOp, acc::CreateOp,
|
||||
acc::DevicePtrOp, acc::GetDevicePtrOp, acc::PresentOp,
|
||||
acc::DeclareDeviceResidentOp, acc::DeclareLinkOp>(
|
||||
@@ -995,6 +995,32 @@ static LogicalResult checkDeclareOperands(Op &op,
|
||||
return op.emitError(
|
||||
"expect valid declare data entry operation or acc.getdeviceptr "
|
||||
"as defining op");
|
||||
|
||||
mlir::Value varPtr{getVarPtr(operand.getDefiningOp())};
|
||||
assert(varPtr && "declare operands can only be data entry operations which "
|
||||
"must have varPtr");
|
||||
std::optional<mlir::acc::DataClause> dataClauseOptional{
|
||||
getDataClause(operand.getDefiningOp())};
|
||||
assert(dataClauseOptional.has_value() &&
|
||||
"declare operands can only be data entry operations which must have "
|
||||
"dataClause");
|
||||
|
||||
// If varPtr has no defining op - there is nothing to check further.
|
||||
if (!varPtr.getDefiningOp())
|
||||
continue;
|
||||
|
||||
// Check that the varPtr has a declare attribute.
|
||||
auto declareAttribute{
|
||||
varPtr.getDefiningOp()->getAttr(mlir::acc::getDeclareAttrName())};
|
||||
if (!declareAttribute)
|
||||
return op.emitError(
|
||||
"expect declare attribute on variable in declare operation");
|
||||
if (llvm::cast<DataClauseAttr>(declareAttribute).getValue() !=
|
||||
dataClauseOptional.value())
|
||||
return op.emitError(
|
||||
"expect matching declare attribute on variable in declare operation");
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
@@ -1106,3 +1132,26 @@ LogicalResult acc::WaitOp::verify() {
|
||||
|
||||
#define GET_TYPEDEF_CLASSES
|
||||
#include "mlir/Dialect/OpenACC/OpenACCOpsTypes.cpp.inc"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// acc dialect utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
mlir::Value mlir::acc::getVarPtr(mlir::Operation *accDataEntryOp) {
|
||||
auto varPtr{llvm::TypeSwitch<mlir::Operation *, mlir::Value>(accDataEntryOp)
|
||||
.Case<ACC_DATA_ENTRY_OPS>(
|
||||
[&](auto entry) { return entry.getVarPtr(); })
|
||||
.Default([&](mlir::Operation *) { return mlir::Value(); })};
|
||||
return varPtr;
|
||||
}
|
||||
|
||||
std::optional<mlir::acc::DataClause>
|
||||
mlir::acc::getDataClause(mlir::Operation *accDataEntryOp) {
|
||||
auto dataClause{
|
||||
llvm::TypeSwitch<mlir::Operation *, std::optional<mlir::acc::DataClause>>(
|
||||
accDataEntryOp)
|
||||
.Case<ACC_DATA_ENTRY_OPS>(
|
||||
[&](auto entry) { return entry.getDataClause(); })
|
||||
.Default([&](mlir::Operation *) { return std::nullopt; })};
|
||||
return dataClause;
|
||||
}
|
||||
|
||||
@@ -1605,20 +1605,20 @@ func.func @testdeclareop(%a: memref<f32>, %b: memref<f32>, %c: memref<f32>) -> (
|
||||
|
||||
// -----
|
||||
|
||||
llvm.mlir.global external @globalvar() : i32 {
|
||||
llvm.mlir.global external @globalvar() { acc.declare = #acc<data_clause acc_create> } : i32 {
|
||||
%0 = llvm.mlir.constant(0 : i32) : i32
|
||||
llvm.return %0 : i32
|
||||
}
|
||||
|
||||
acc.global_ctor @acc_constructor {
|
||||
%0 = llvm.mlir.addressof @globalvar : !llvm.ptr<i32>
|
||||
%0 = llvm.mlir.addressof @globalvar { acc.declare = #acc<data_clause acc_create> } : !llvm.ptr<i32>
|
||||
%1 = acc.create varPtr(%0 : !llvm.ptr<i32>) -> !llvm.ptr<i32>
|
||||
acc.declare_enter dataOperands(%1 : !llvm.ptr<i32>)
|
||||
acc.terminator
|
||||
}
|
||||
|
||||
acc.global_dtor @acc_destructor {
|
||||
%0 = llvm.mlir.addressof @globalvar : !llvm.ptr<i32>
|
||||
%0 = llvm.mlir.addressof @globalvar { acc.declare = #acc<data_clause acc_create> } : !llvm.ptr<i32>
|
||||
%1 = acc.getdeviceptr varPtr(%0 : !llvm.ptr<i32>) -> !llvm.ptr<i32> { dataClause = #acc<data_clause acc_create>}
|
||||
acc.declare_exit dataOperands(%1 : !llvm.ptr<i32>)
|
||||
acc.delete accPtr(%1 : !llvm.ptr<i32>)
|
||||
@@ -1626,11 +1626,11 @@ acc.global_dtor @acc_destructor {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: acc.global_ctor @acc_constructor
|
||||
// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @globalvar : !llvm.ptr<i32>
|
||||
// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @globalvar {acc.declare = #acc<data_clause acc_create>} : !llvm.ptr<i32>
|
||||
// CHECK-NEXT: %[[CREATE:.*]] = acc.create varPtr(%[[ADDR]] : !llvm.ptr<i32>) -> !llvm.ptr<i32>
|
||||
// CHECK-NEXT: acc.declare_enter dataOperands(%[[CREATE]] : !llvm.ptr<i32>)
|
||||
// CHECK: acc.global_dtor @acc_destructor
|
||||
// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @globalvar : !llvm.ptr<i32>
|
||||
// CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @globalvar {acc.declare = #acc<data_clause acc_create>} : !llvm.ptr<i32>
|
||||
// CHECK-NEXT: %[[DELETE:.*]] = acc.getdeviceptr varPtr(%[[ADDR]] : !llvm.ptr<i32>) -> !llvm.ptr<i32> {dataClause = #acc<data_clause acc_create>}
|
||||
// CHECK-NEXT: acc.declare_exit dataOperands(%[[DELETE]] : !llvm.ptr<i32>)
|
||||
// CHECK-NEXT: acc.delete accPtr(%[[DELETE]] : !llvm.ptr<i32>)
|
||||
|
||||
Reference in New Issue
Block a user