addOperand(operands, operandSegments, async);
addOperand(operands, operandSegments, waitDevnum);
addOperands(operands, operandSegments, waitOperands);
- operandSegments.append({0, 0, 0});
addOperands(operands, operandSegments, dataClauseOperands);
mlir::acc::ExitDataOp exitDataOp = createSimpleOp<mlir::acc::ExitDataOp>(
fir::LLVMTypeConverter converter(
op.getOperation()->getParentOfType<mlir::ModuleOp>(), true);
patterns.add<LegalizeDataOpForLLVMTranslation<acc::DataOp>>(converter);
- patterns.add<LegalizeDataOpForLLVMTranslation<acc::ExitDataOp>>(converter);
patterns.add<LegalizeDataOpForLLVMTranslation<acc::ParallelOp>>(converter);
ConversionTarget target(*context);
allDataOperandsAreConverted(op.getAttachOperands());
});
- target.addDynamicallyLegalOp<acc::ExitDataOp>(
- [allDataOperandsAreConverted](acc::ExitDataOp op) {
- return allDataOperandsAreConverted(op.getCopyoutOperands()) &&
- allDataOperandsAreConverted(op.getDeleteOperands()) &&
- allDataOperandsAreConverted(op.getDetachOperands());
- });
-
target.addDynamicallyLegalOp<acc::ParallelOp>(
[allDataOperandsAreConverted](acc::ParallelOp op) {
return allDataOperandsAreConverted(op.getReductionOperands()) &&
fir.has_value %0 : !fir.array<10xf32>
}
-func.func @_QQsub_enter_exit() attributes {fir.bindc_name = "a"} {
- %0 = fir.address_of(@_QFEa) : !fir.ref<!fir.array<10xf32>>
- acc.exit_data copyout(%0 : !fir.ref<!fir.array<10xf32>>)
- return
-}
-
-// CHECK-LABEL: func.func @_QQsub_enter_exit() attributes {fir.bindc_name = "a"} {
-// CHECK: %[[ADDR:.*]] = fir.address_of(@_QFEa) : !fir.ref<!fir.array<10xf32>>
-// CHECK: %[[CAST1:.*]] = builtin.unrealized_conversion_cast %[[ADDR]] : !fir.ref<!fir.array<10xf32>> to !llvm.ptr<array<10 x f32>>
-// CHECK: acc.exit_data copyout(%[[CAST1]] : !llvm.ptr<array<10 x f32>>)
-
-// LLVMIR-LABEL: llvm.func @_QQsub_enter_exit() attributes {fir.bindc_name = "a"} {
-// LLVMIR: %[[ADDR:.*]] = llvm.mlir.addressof @_QFEa : !llvm.ptr<array<10 x f32>>
-// LLVMIR: acc.exit_data copyout(%[[ADDR]] : !llvm.ptr<array<10 x f32>>)
-
-// -----
-
-fir.global internal @_QFEa : !fir.array<10xf32> {
- %0 = fir.undefined !fir.array<10xf32>
- fir.has_value %0 : !fir.array<10xf32>
-}
-
func.func @_QQsub_parallel() attributes {fir.bindc_name = "test"} {
%0 = fir.address_of(@_QFEa) : !fir.ref<!fir.array<10xf32>>
%1 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
Optional<IntOrIndex>:$waitDevnum,
Variadic<IntOrIndex>:$waitOperands,
UnitAttr:$wait,
- Variadic<AnyType>:$copyoutOperands,
- Variadic<AnyType>:$deleteOperands,
- Variadic<AnyType>:$detachOperands,
Variadic<OpenACC_PointerLikeTypeInterface>:$dataClauseOperands,
UnitAttr:$finalize);
| `async` `(` $asyncOperand `:` type($asyncOperand) `)`
| `wait_devnum` `(` $waitDevnum `:` type($waitDevnum) `)`
| `wait` `(` $waitOperands `:` type($waitOperands) `)`
- | `copyout` `(` $copyoutOperands `:` type($copyoutOperands) `)`
- | `delete` `(` $deleteOperands `:` type($deleteOperands) `)`
- | `detach` `(` $detachOperands `:` type($detachOperands) `)`
| `dataOperands` `(` $dataClauseOperands `:` type($dataClauseOperands) `)`
)
attr-dict-with-keyword
void mlir::populateOpenACCToLLVMConversionPatterns(
LLVMTypeConverter &converter, RewritePatternSet &patterns) {
patterns.add<LegalizeDataOpForLLVMTranslation<acc::DataOp>>(converter);
- patterns.add<LegalizeDataOpForLLVMTranslation<acc::ExitDataOp>>(converter);
patterns.add<LegalizeDataOpForLLVMTranslation<acc::ParallelOp>>(converter);
}
allDataOperandsAreConverted(op.getAttachOperands());
});
- target.addDynamicallyLegalOp<acc::ExitDataOp>(
- [allDataOperandsAreConverted](acc::ExitDataOp op) {
- return allDataOperandsAreConverted(op.getCopyoutOperands()) &&
- allDataOperandsAreConverted(op.getDeleteOperands()) &&
- allDataOperandsAreConverted(op.getDetachOperands());
- });
-
target.addDynamicallyLegalOp<acc::ParallelOp>(
[allDataOperandsAreConverted](acc::ParallelOp op) {
return allDataOperandsAreConverted(op.getReductionOperands()) &&
// 2.6.6. Data Exit Directive restriction
// At least one copyout, delete, or detach clause must appear on an exit data
// directive.
- if (getCopyoutOperands().empty() && getDeleteOperands().empty() &&
- getDetachOperands().empty() && getDataClauseOperands().empty())
- return emitError(
- "at least one operand in copyout, delete or detach must appear on the "
- "exit data operation");
+ if (getDataClauseOperands().empty())
+ return emitError("at least one operand must be present in dataOperands on "
+ "the exit data operation");
// The async attribute represent the async clause without value. Therefore the
// attribute and operand cannot appear at the same time.
}
unsigned ExitDataOp::getNumDataOperands() {
- return getCopyoutOperands().size() + getDeleteOperands().size() +
- getDetachOperands().size() + getDataClauseOperands().size();
+ return getDataClauseOperands().size();
}
Value ExitDataOp::getDataOperand(unsigned i) {
unsigned index = 0;
+ llvm::SmallVector<mlir::Value> deleteOperands, copyoutOperands;
+ for (mlir::Value dataOp : op.getDataClauseOperands()) {
+ if (auto devicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
+ dataOp.getDefiningOp())) {
+ for (auto &u : devicePtrOp.getAccPtr().getUses()) {
+ if (mlir::dyn_cast_or_null<acc::DeleteOp>(u.getOwner()))
+ deleteOperands.push_back(devicePtrOp.getVarPtr());
+ else if (mlir::dyn_cast_or_null<acc::CopyoutOp>(u.getOwner()))
+ copyoutOperands.push_back(devicePtrOp.getVarPtr());
+ }
+ }
+ }
+
+ auto nbTotalOperands = deleteOperands.size() + copyoutOperands.size();
+
// Delete operands are handled as `delete` call.
- if (failed(processOperands(builder, moduleTranslation, op,
- op.getDeleteOperands(), op.getNumDataOperands(),
- kDeleteFlag, flags, names, index, mapperAllocas)))
+ if (failed(processOperands(builder, moduleTranslation, op, deleteOperands,
+ nbTotalOperands, kDeleteFlag, flags, names, index,
+ mapperAllocas)))
return failure();
// Copyout operands are handled as `from` call.
- if (failed(processOperands(builder, moduleTranslation, op,
- op.getCopyoutOperands(), op.getNumDataOperands(),
- kHostCopyoutFlag, flags, names, index,
- mapperAllocas)))
+ if (failed(processOperands(builder, moduleTranslation, op, copyoutOperands,
+ nbTotalOperands, kHostCopyoutFlag, flags, names,
+ index, mapperAllocas)))
return failure();
return success();
"unexpected OpenACC terminator with operands");
return success();
})
- .Case<acc::CreateOp, acc::CopyinOp, acc::UpdateDeviceOp>([](auto op) {
+ .Case<acc::CreateOp, acc::CopyinOp, acc::CopyoutOp, acc::DeleteOp,
+ acc::UpdateDeviceOp, acc::GetDevicePtrOp>([](auto op) {
// NOP
return success();
})
// RUN: mlir-opt -convert-openacc-to-llvm='use-opaque-pointers=1' -split-input-file %s | FileCheck %s
-func.func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
- acc.exit_data copyout(%b : memref<10xf32>) delete(%a : memref<10xf32>)
- return
-}
-
-// CHECK: acc.exit_data copyout(%{{.*}} : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>) delete(%{{.*}} : !llvm.struct<"openacc_data.1", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>)
-
-// -----
-
-func.func @testexitdataop(%a: !llvm.ptr, %b: memref<10xf32>) -> () {
- acc.exit_data copyout(%b : memref<10xf32>) delete(%a : !llvm.ptr)
- return
-}
-
-// CHECK: acc.exit_data copyout(%{{.*}} : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>) delete(%{{.*}} : !llvm.ptr)
-
-// -----
-
-func.func @testexitdataop(%a: memref<10xi64>, %b: memref<10xf32>) -> () {
- acc.exit_data copyout(%b : memref<10xf32>) delete(%a : memref<10xi64>) attributes {async}
- return
-}
-
-// CHECK: acc.exit_data copyout(%{{.*}} : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>) delete(%{{.*}} : !llvm.struct<"openacc_data.1", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>) attributes {async}
-
-// -----
-
-func.func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
- %ifCond = arith.constant true
- acc.exit_data if(%ifCond) copyout(%b : memref<10xf32>) delete(%a : memref<10xf32>)
- return
-}
-
-// CHECK: acc.exit_data if(%{{.*}}) copyout(%{{.*}} : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>) delete(%{{.*}} : !llvm.struct<"openacc_data.1", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>)
-
-// -----
-
func.func @testdataregion(%a: memref<10xf32>, %b: memref<10xf32>) -> () {
acc.data copy(%b : memref<10xf32>) copyout(%a : memref<10xf32>) {
acc.parallel {
// -----
-func.func @testexitdataop(%a: memref<10xf32>, %ifCond: i1) -> () {
- acc.exit_data if(%ifCond) delete(%a: memref<10xf32>)
+func.func @testexitdataop(%a: memref<f32>, %ifCond: i1) -> () {
+ %0 = acc.getdeviceptr varPtr(%a : memref<f32>) -> memref<f32>
+ acc.exit_data if(%ifCond) dataOperands(%0 : memref<f32>)
+ acc.delete accPtr(%0 : memref<f32>)
return
}
-// CHECK: func @testexitdataop(%{{.*}}: memref<10xf32>, [[IFCOND:%.*]]: i1)
+// CHECK: func @testexitdataop(%{{.*}}: memref<f32>, [[IFCOND:%.*]]: i1)
// CHECK: scf.if [[IFCOND]] {
-// CHECK-NEXT: acc.exit_data delete(%{{.*}} : memref<10xf32>)
+// CHECK-NEXT: acc.exit_data dataOperands(%{{.*}} : memref<f32>)
// CHECK-NEXT: }
// -----
// -----
-func.func @exit_data_true(%d1 : memref<10xf32>) {
+func.func @exit_data_true(%d1 : memref<f32>) {
%true = arith.constant true
- acc.exit_data if(%true) delete(%d1 : memref<10xf32>) attributes {async}
+ %0 = acc.getdeviceptr varPtr(%d1 : memref<f32>) -> memref<f32>
+ acc.exit_data if(%true) dataOperands(%0 : memref<f32>) attributes {async}
+ acc.delete accPtr(%0 : memref<f32>)
return
}
// CHECK-LABEL: func.func @exit_data_true
// CHECK-NOT:if
-// CHECK:acc.exit_data delete
+// CHECK:acc.exit_data dataOperands
// -----
-func.func @exit_data_false(%d1 : memref<10xf32>) {
+func.func @exit_data_false(%d1 : memref<f32>) {
%false = arith.constant false
- acc.exit_data if(%false) delete(%d1 : memref<10xf32>) attributes {async}
+ %0 = acc.getdeviceptr varPtr(%d1 : memref<f32>) -> memref<f32>
+ acc.exit_data if(%false) dataOperands(%0 : memref<f32>) attributes {async}
+ acc.delete accPtr(%0 : memref<f32>)
return
}
// -----
-func.func @testexitdataop(%a: memref<10xf32>) -> () {
+func.func @testexitdataop(%a: memref<f32>) -> () {
%ifCond = arith.constant true
- acc.exit_data if(%ifCond) delete(%a: memref<10xf32>)
+ %0 = acc.getdeviceptr varPtr(%a : memref<f32>) -> memref<f32>
+ acc.exit_data if(%ifCond) dataOperands(%0 : memref<f32>)
+ acc.delete accPtr(%0 : memref<f32>)
return
}
-// CHECK: acc.exit_data delete(%{{.*}} : memref<10xf32>)
+// CHECK: acc.exit_data dataOperands(%{{.*}} : memref<f32>)
// -----
-func.func @testexitdataop(%a: memref<10xf32>) -> () {
+func.func @testexitdataop(%a: memref<f32>) -> () {
%ifCond = arith.constant false
- acc.exit_data if(%ifCond) delete(%a: memref<10xf32>)
+ %0 = acc.getdeviceptr varPtr(%a : memref<f32>) -> memref<f32>
+ acc.exit_data if(%ifCond) dataOperands(%0 : memref<f32>)
+ acc.delete accPtr(%0 : memref<f32>)
return
}
// -----
-func.func @testexitdataop(%a: memref<10xf32>, %ifCond: i1) -> () {
- acc.exit_data if(%ifCond) delete(%a: memref<10xf32>)
+func.func @testexitdataop(%a: memref<f32>, %ifCond: i1) -> () {
+ %0 = acc.getdeviceptr varPtr(%a : memref<f32>) -> memref<f32>
+ acc.exit_data if(%ifCond) dataOperands(%0 : memref<f32>)
+ acc.delete accPtr(%0 : memref<f32>)
return
}
-// CHECK: func @testexitdataop(%{{.*}}: memref<10xf32>, [[IFCOND:%.*]]: i1)
-// CHECK: acc.exit_data if(%{{.*}}) delete(%{{.*}} : memref<10xf32>)
+// CHECK: func @testexitdataop(%{{.*}}: memref<f32>, [[IFCOND:%.*]]: i1)
+// CHECK: acc.exit_data if(%{{.*}}) dataOperands(%{{.*}} : memref<f32>)
// -----
// -----
-// expected-error@+1 {{at least one operand in copyout, delete or detach must appear on the exit data operation}}
+// expected-error@+1 {{at least one operand must be present in dataOperands on the exit data operation}}
acc.exit_data attributes {async}
// -----
%cst = arith.constant 1 : index
-%value = memref.alloc() : memref<10xf32>
+%value = memref.alloc() : memref<f32>
+%0 = acc.getdeviceptr varPtr(%value : memref<f32>) -> memref<f32>
// expected-error@+1 {{async attribute cannot appear with asyncOperand}}
-acc.exit_data async(%cst: index) delete(%value : memref<10xf32>) attributes {async}
+acc.exit_data async(%cst: index) dataOperands(%0 : memref<f32>) attributes {async}
+acc.delete accPtr(%0 : memref<f32>)
// -----
%cst = arith.constant 1 : index
-%value = memref.alloc() : memref<10xf32>
+%value = memref.alloc() : memref<f32>
+%0 = acc.getdeviceptr varPtr(%value : memref<f32>) -> memref<f32>
// expected-error@+1 {{wait_devnum cannot appear without waitOperands}}
-acc.exit_data wait_devnum(%cst: index) delete(%value : memref<10xf32>)
+acc.exit_data wait_devnum(%cst: index) dataOperands(%0 : memref<f32>)
+acc.delete accPtr(%0 : memref<f32>)
// -----
// -----
-func.func @testexitdataop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x10xf32>) -> () {
+func.func @testexitdataop(%a: !llvm.ptr<f32>) -> () {
%ifCond = arith.constant true
%i64Value = arith.constant 1 : i64
%i32Value = arith.constant 1 : i32
%idxValue = arith.constant 1 : index
- acc.exit_data copyout(%a : memref<10xf32>)
- acc.exit_data delete(%a : memref<10xf32>)
- acc.exit_data delete(%a : memref<10xf32>) attributes {async,finalize}
- acc.exit_data detach(%a : memref<10xf32>)
- acc.exit_data copyout(%a : memref<10xf32>) attributes {async}
- acc.exit_data delete(%a : memref<10xf32>) attributes {wait}
- acc.exit_data async(%i64Value : i64) copyout(%a : memref<10xf32>)
- acc.exit_data copyout(%a : memref<10xf32>) async(%i64Value : i64)
- acc.exit_data if(%ifCond) copyout(%a : memref<10xf32>)
- acc.exit_data wait_devnum(%i64Value: i64) wait(%i32Value, %idxValue : i32, index) copyout(%a : memref<10xf32>)
+ %0 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%0 : !llvm.ptr<f32>)
+ acc.copyout accPtr(%0 : !llvm.ptr<f32>) to varPtr(%a : !llvm.ptr<f32>)
+
+ %1 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%1 : !llvm.ptr<f32>)
+ acc.delete accPtr(%1 : !llvm.ptr<f32>)
+
+ %2 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%2 : !llvm.ptr<f32>) attributes {async,finalize}
+ acc.delete accPtr(%2 : !llvm.ptr<f32>)
+
+ %3 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%3 : !llvm.ptr<f32>)
+ acc.detach accPtr(%3 : !llvm.ptr<f32>)
+
+ %4 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%4 : !llvm.ptr<f32>) attributes {async}
+ acc.copyout accPtr(%4 : !llvm.ptr<f32>) to varPtr(%a : !llvm.ptr<f32>)
+
+ %5 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%5 : !llvm.ptr<f32>) attributes {wait}
+ acc.delete accPtr(%5 : !llvm.ptr<f32>)
+
+ %6 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data async(%i64Value : i64) dataOperands(%6 : !llvm.ptr<f32>)
+ acc.copyout accPtr(%6 : !llvm.ptr<f32>) to varPtr(%a : !llvm.ptr<f32>)
+
+ %7 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%7 : !llvm.ptr<f32>) async(%i64Value : i64)
+ acc.copyout accPtr(%7 : !llvm.ptr<f32>) to varPtr(%a : !llvm.ptr<f32>)
+
+ %8 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data if(%ifCond) dataOperands(%8 : !llvm.ptr<f32>)
+ acc.copyout accPtr(%8 : !llvm.ptr<f32>) to varPtr(%a : !llvm.ptr<f32>)
+
+ %9 = acc.getdeviceptr varPtr(%a : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data wait_devnum(%i64Value: i64) wait(%i32Value, %idxValue : i32, index) dataOperands(%9 : !llvm.ptr<f32>)
+ acc.copyout accPtr(%9 : !llvm.ptr<f32>) to varPtr(%a : !llvm.ptr<f32>)
return
}
-// CHECK: func @testexitdataop([[ARGA:%.*]]: memref<10xf32>, [[ARGB:%.*]]: memref<10xf32>, [[ARGC:%.*]]: memref<10x10xf32>) {
-// CHECK: [[IFCOND1:%.*]] = arith.constant true
-// CHECK: [[I64VALUE:%.*]] = arith.constant 1 : i64
-// CHECK: [[I32VALUE:%.*]] = arith.constant 1 : i32
-// CHECK: [[IDXVALUE:%.*]] = arith.constant 1 : index
-// CHECK: acc.exit_data copyout([[ARGA]] : memref<10xf32>)
-// CHECK: acc.exit_data delete([[ARGA]] : memref<10xf32>)
-// CHECK: acc.exit_data delete([[ARGA]] : memref<10xf32>) attributes {async, finalize}
-// CHECK: acc.exit_data detach([[ARGA]] : memref<10xf32>)
-// CHECK: acc.exit_data copyout([[ARGA]] : memref<10xf32>) attributes {async}
-// CHECK: acc.exit_data delete([[ARGA]] : memref<10xf32>) attributes {wait}
-// CHECK: acc.exit_data async([[I64VALUE]] : i64) copyout([[ARGA]] : memref<10xf32>)
-// CHECK: acc.exit_data async([[I64VALUE]] : i64) copyout([[ARGA]] : memref<10xf32>)
-// CHECK: acc.exit_data if([[IFCOND]]) copyout([[ARGA]] : memref<10xf32>)
-// CHECK: acc.exit_data wait_devnum([[I64VALUE]] : i64) wait([[I32VALUE]], [[IDXVALUE]] : i32, index) copyout([[ARGA]] : memref<10xf32>)
+// CHECK: func @testexitdataop(%[[ARGA:.*]]: !llvm.ptr<f32>) {
+// CHECK: %[[IFCOND:.*]] = arith.constant true
+// CHECK: %[[I64VALUE:.*]] = arith.constant 1 : i64
+// CHECK: %[[I32VALUE:.*]] = arith.constant 1 : i32
+// CHECK: %[[IDXVALUE:.*]] = arith.constant 1 : index
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.copyout accPtr(%[[DEVPTR]] : !llvm.ptr<f32>) to varPtr(%[[ARGA]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.delete accPtr(%[[DEVPTR]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>) attributes {async, finalize}
+// CHECK: acc.delete accPtr(%[[DEVPTR]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.detach accPtr(%[[DEVPTR]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>) attributes {async}
+// CHECK: acc.copyout accPtr(%[[DEVPTR]] : !llvm.ptr<f32>) to varPtr(%[[ARGA]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>) attributes {wait}
+// CHECK: acc.delete accPtr(%[[DEVPTR]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data async(%[[I64VALUE]] : i64) dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.copyout accPtr(%[[DEVPTR]] : !llvm.ptr<f32>) to varPtr(%[[ARGA]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data async(%[[I64VALUE]] : i64) dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.copyout accPtr(%[[DEVPTR]] : !llvm.ptr<f32>) to varPtr(%[[ARGA]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data if(%[[IFCOND]]) dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.copyout accPtr(%[[DEVPTR]] : !llvm.ptr<f32>) to varPtr(%[[ARGA]] : !llvm.ptr<f32>)
+
+// CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[ARGA]] : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+// CHECK: acc.exit_data wait_devnum(%[[I64VALUE]] : i64) wait(%[[I32VALUE]], %[[IDXVALUE]] : i32, index) dataOperands(%[[DEVPTR]] : !llvm.ptr<f32>)
+// CHECK: acc.copyout accPtr(%[[DEVPTR]] : !llvm.ptr<f32>) to varPtr(%[[ARGA]] : !llvm.ptr<f32>)
+
// -----
}
// CHECK: func @testenterdataop(%[[ARGA:.*]]: !llvm.ptr<f32>, %[[ARGB:.*]]: !llvm.ptr<f32>, %[[ARGC:.*]]: !llvm.ptr<f32>) {
-// CHECK: [[IFCOND1:%.*]] = arith.constant true
+// CHECK: [[IFCOND:%.*]] = arith.constant true
// CHECK: [[I64VALUE:%.*]] = arith.constant 1 : i64
// CHECK: [[I32VALUE:%.*]] = arith.constant 1 : i32
// CHECK: [[IDXVALUE:%.*]] = arith.constant 1 : index
// -----
-llvm.func @testexitdataop(%arg0: !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, %arg1: !llvm.ptr<f32>) {
- %0 = llvm.mlir.constant(10 : index) : i64
- %1 = llvm.mlir.null : !llvm.ptr<f32>
- %2 = llvm.getelementptr %1[%0] : (!llvm.ptr<f32>, i64) -> !llvm.ptr<f32>
- %3 = llvm.ptrtoint %2 : !llvm.ptr<f32> to i64
- %4 = llvm.extractvalue %arg0[1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>
- %5 = llvm.mlir.undef : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
- %6 = llvm.insertvalue %arg0, %5[0] : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
- %7 = llvm.insertvalue %4, %6[1] : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
- %8 = llvm.insertvalue %3, %7[2] : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>
- acc.exit_data copyout(%arg1 : !llvm.ptr<f32>) delete(%8 : !llvm.struct<"openacc_data", (struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>, ptr<f32>, i64)>)
+llvm.func @testexitdataop(%arg0: !llvm.ptr<f32>, %arg1: !llvm.ptr<f32>) {
+ %arg0_devptr = acc.getdeviceptr varPtr(%arg0 : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ %1 = acc.getdeviceptr varPtr(%arg1 : !llvm.ptr<f32>) -> !llvm.ptr<f32>
+ acc.exit_data dataOperands(%arg0_devptr, %1 : !llvm.ptr<f32>, !llvm.ptr<f32>)
+ acc.delete accPtr(%arg0_devptr : !llvm.ptr<f32>)
+ acc.copyout accPtr(%1 : !llvm.ptr<f32>) to varPtr(%arg1 : !llvm.ptr<f32>)
llvm.return
}
// CHECK: %struct.ident_t = type { i32, i32, i32, i32, ptr }
-// CHECK: [[LOCSTR:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};testexitdataop;{{[0-9]*}};{{[0-9]*}};;\00", align 1
-// CHECK: [[LOCGLOBAL:@.*]] = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 {{[0-9]*}}, ptr [[LOCSTR]] }, align 8
-// CHECK: [[MAPNAME1:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00", align 1
-// CHECK: [[MAPNAME2:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00", align 1
-// CHECK: [[MAPTYPES:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i64] [i64 8, i64 2]
-// CHECK: [[MAPNAMES:@.*]] = private constant [{{[0-9]*}} x ptr] [ptr [[MAPNAME1]], ptr [[MAPNAME2]]]
+// CHECK: @[[LOCSTR:.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};testexitdataop;{{[0-9]*}};{{[0-9]*}};;\00"
+// CHECK: @[[LOCGLOBAL:.*]] = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 {{[0-9]*}}, ptr @[[LOCSTR]] }
+// CHECK: @[[MAPNAME1:.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00"
+// CHECK: @[[MAPNAME2:.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00"
+// CHECK: @[[MAPTYPES:.*]] = private unnamed_addr constant [{{[0-9]*}} x i64] [i64 8, i64 2]
+// CHECK: @[[MAPNAMES:.*]] = private constant [{{[0-9]*}} x ptr] [ptr @[[MAPNAME1]], ptr @[[MAPNAME2]]]
-// CHECK: define void @testexitdataop({ ptr, ptr, i64, [1 x i64], [1 x i64] } %{{.*}}, ptr [[SIMPLEPTR:%.*]])
-// CHECK: [[ARGBASE_ALLOCA:%.*]] = alloca [{{[0-9]*}} x ptr], align 8
-// CHECK: [[ARG_ALLOCA:%.*]] = alloca [{{[0-9]*}} x ptr], align 8
-// CHECK: [[SIZE_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i64], align 8
+// CHECK: define void @testexitdataop(ptr %[[PTR0:.*]], ptr %[[PTR1:.*]])
+// CHECK: %[[OFFLOAD_BASEPTRS:.*]] = alloca [{{[0-9]*}} x ptr]
+// CHECK: %[[OFFLOAD_PTRS:.*]] = alloca [{{[0-9]*}} x ptr]
+// CHECK: %[[OFFLOAS_SIZES:.*]] = alloca [{{[0-9]*}} x i64]
-// CHECK: [[ARGBASE:%.*]] = extractvalue %openacc_data %{{.*}}, 0
-// CHECK: [[ARG:%.*]] = extractvalue %openacc_data %{{.*}}, 1
-// CHECK: [[ARGSIZE:%.*]] = extractvalue %openacc_data %{{.*}}, 2
-// CHECK: [[ARGBASEGEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ARGBASE_ALLOCA]], i32 0, i32 0
-// CHECK: store { ptr, ptr, i64, [1 x i64], [1 x i64] } [[ARGBASE]], ptr [[ARGBASEGEP]], align 8
-// CHECK: [[ARGGEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ARG_ALLOCA]], i32 0, i32 0
-// CHECK: store ptr [[ARG]], ptr [[ARGGEP]], align 8
-// CHECK: [[SIZEGEP:%.*]] = getelementptr inbounds [2 x i64], ptr [[SIZE_ALLOCA]], i32 0, i32 0
-// CHECK: store i64 [[ARGSIZE]], ptr [[SIZEGEP]], align 4
+// CHECK: %[[OFFLOAD_BASEPTRS_GEP:.*]] = getelementptr inbounds [2 x ptr], ptr %[[OFFLOAD_BASEPTRS]], i32 0, i32 0
+// CHECK: store ptr %[[PTR0]], ptr %[[OFFLOAD_BASEPTRS_GEP]]
+// CHECK: %[[OFFLOAD_PTRS_GEP:.*]] = getelementptr inbounds [2 x ptr], ptr %[[OFFLOAD_PTRS]], i32 0, i32 0
+// CHECK: store ptr %[[PTR0]], ptr %[[OFFLOAD_PTRS_GEP]]
+// CHECK: %[[OFFLOAS_SIZES_GEP:.*]] = getelementptr inbounds [2 x i64], ptr %[[OFFLOAS_SIZES]], i32 0, i32 0
+// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[OFFLOAS_SIZES_GEP]]
-// CHECK: [[ARGBASEGEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ARGBASE_ALLOCA]], i32 0, i32 1
-// CHECK: store ptr [[SIMPLEPTR]], ptr [[ARGBASEGEP]], align 8
-// CHECK: [[ARGGEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ARG_ALLOCA]], i32 0, i32 1
-// CHECK: store ptr [[SIMPLEPTR]], ptr [[ARGGEP]], align 8
-// CHECK: [[SIZEGEP:%.*]] = getelementptr inbounds [2 x i64], ptr [[SIZE_ALLOCA]], i32 0, i32 1
-// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr [[SIZEGEP]], align 4
+// CHECK: %[[OFFLOAD_BASEPTRS_GEP:.*]] = getelementptr inbounds [2 x ptr], ptr %[[OFFLOAD_BASEPTRS]], i32 0, i32 1
+// CHECK: store ptr %[[PTR1]], ptr %[[OFFLOAD_BASEPTRS_GEP]]
+// CHECK: %[[OFFLOAD_PTRS_GEP:.*]] = getelementptr inbounds [2 x ptr], ptr %[[OFFLOAD_PTRS]], i32 0, i32 1
+// CHECK: store ptr %[[PTR1]], ptr %[[OFFLOAD_PTRS_GEP]]
+// CHECK: %[[OFFLOAS_SIZES_GEP:.*]] = getelementptr inbounds [2 x i64], ptr %[[OFFLOAS_SIZES]], i32 0, i32 1
+// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[OFFLOAS_SIZES_GEP]]
-// CHECK: [[ARGBASE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ARGBASE_ALLOCA]], i32 0, i32 0
-// CHECK: [[ARG_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x ptr], ptr [[ARG_ALLOCA]], i32 0, i32 0
-// CHECK: [[SIZE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i64], ptr [[SIZE_ALLOCA]], i32 0, i32 0
+// CHECK: %[[OFFLOAD_BASEPTRS_GEP:.*]] = getelementptr inbounds [2 x ptr], ptr %[[OFFLOAD_BASEPTRS]], i32 0, i32 0
+// CHECK: %[[OFFLOAD_PTRS_GEP:.*]] = getelementptr inbounds [2 x ptr], ptr %[[OFFLOAD_PTRS]], i32 0, i32 0
+// CHECK: %[[OFFLOAS_SIZES_GEP:.*]] = getelementptr inbounds [2 x i64], ptr %[[OFFLOAS_SIZES]], i32 0, i32 0
-// CHECK: call void @__tgt_target_data_end_mapper(ptr [[LOCGLOBAL]], i64 -1, i32 2, ptr [[ARGBASE_ALLOCA_GEP]], ptr [[ARG_ALLOCA_GEP]], ptr [[SIZE_ALLOCA_GEP]], ptr [[MAPTYPES]], ptr [[MAPNAMES]], ptr null)
+// CHECK: call void @__tgt_target_data_end_mapper(ptr @[[LOCGLOBAL]], i64 -1, i32 2, ptr %[[OFFLOAD_BASEPTRS_GEP]], ptr %[[OFFLOAD_PTRS_GEP]], ptr %[[OFFLOAS_SIZES_GEP]], ptr @[[MAPTYPES]], ptr @[[MAPNAMES]], ptr null)
// CHECK: declare void @__tgt_target_data_end_mapper(ptr, i64, i32, ptr, ptr, ptr, ptr, ptr, ptr) #0