diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -259,6 +259,173 @@ return bounds; } +static mlir::Value +getDataOperandBaseAddr(Fortran::lower::AbstractConverter &converter, + fir::FirOpBuilder &builder, + Fortran::lower::SymbolRef sym, mlir::Location loc) { + mlir::Value symAddr = converter.getSymbolAddress(sym); + // TODO: Might need revisiting to handle for non-shared clauses + if (!symAddr) { + if (const auto *details = + sym->detailsIf()) + symAddr = converter.getSymbolAddress(details->symbol()); + } + + if (!symAddr) + llvm::report_fatal_error("could not retrieve symbol address"); + + if (auto boxTy = + fir::unwrapRefType(symAddr.getType()).dyn_cast()) { + if (boxTy.getEleTy().isa()) + TODO(loc, "derived type"); + + // Load the box when baseAddr is a `fir.ref>` or a + // `fir.ref>` type. + if (symAddr.getType().isa()) + return builder.create(loc, symAddr); + } + return symAddr; +} + +static mlir::Value gatherDataOperandAddrAndBounds( + Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder, + Fortran::semantics::SemanticsContext &semanticsContext, + Fortran::lower::StatementContext &stmtCtx, + const Fortran::parser::AccObject &accObject, mlir::Location operandLocation, + std::stringstream &asFortran, llvm::SmallVector &bounds) { + mlir::Value baseAddr; + std::visit( + Fortran::common::visitors{ + [&](const Fortran::parser::Designator &designator) { + if (auto expr{Fortran::semantics::AnalyzeExpr(semanticsContext, + designator)}) { + if ((*expr).Rank() > 0 && + Fortran::parser::Unwrap( + designator)) { + const auto *arrayElement = + Fortran::parser::Unwrap( + designator); + const auto *dataRef = + std::get_if(&designator.u); + fir::ExtendedValue dataExv; + if (Fortran::parser::Unwrap< + Fortran::parser::StructureComponent>( + arrayElement->base)) { + auto exprBase = Fortran::semantics::AnalyzeExpr( + semanticsContext, arrayElement->base); + dataExv = converter.genExprAddr(operandLocation, *exprBase, + stmtCtx); + baseAddr = fir::getBase(dataExv); + asFortran << (*exprBase).AsFortran(); + } else { + const Fortran::parser::Name &name = + Fortran::parser::GetLastName(*dataRef); + baseAddr = getDataOperandBaseAddr( + converter, builder, *name.symbol, operandLocation); + dataExv = converter.getSymbolExtendedValue(*name.symbol); + asFortran << name.ToString(); + } + + if (!arrayElement->subscripts.empty()) { + asFortran << '('; + bounds = genBoundsOps(builder, operandLocation, converter, + stmtCtx, arrayElement->subscripts, + asFortran, dataExv, baseAddr); + } + asFortran << ')'; + } else if (Fortran::parser::Unwrap< + Fortran::parser::StructureComponent>(designator)) { + fir::ExtendedValue compExv = + converter.genExprAddr(operandLocation, *expr, stmtCtx); + baseAddr = fir::getBase(compExv); + if (fir::unwrapRefType(baseAddr.getType()) + .isa()) + bounds = genBaseBoundsOps(builder, operandLocation, converter, + compExv, baseAddr); + asFortran << (*expr).AsFortran(); + + // If the component is an allocatable or pointer the result of + // genExprAddr will be the result of a fir.box_addr operation. + // Retrieve the box so we handle it like other descriptor. + if (auto boxAddrOp = mlir::dyn_cast_or_null( + baseAddr.getDefiningOp())) + baseAddr = boxAddrOp.getVal(); + } else { + // Scalar or full array. + if (const auto *dataRef{ + std::get_if(&designator.u)}) { + const Fortran::parser::Name &name = + Fortran::parser::GetLastName(*dataRef); + fir::ExtendedValue dataExv = + converter.getSymbolExtendedValue(*name.symbol); + baseAddr = getDataOperandBaseAddr( + converter, builder, *name.symbol, operandLocation); + if (fir::unwrapRefType(baseAddr.getType()) + .isa()) + bounds = genBoundsOpsFromBox(builder, operandLocation, + converter, *name.symbol, + baseAddr, (*expr).Rank()); + if (fir::unwrapRefType(baseAddr.getType()) + .isa()) + bounds = genBaseBoundsOps(builder, operandLocation, + converter, dataExv, baseAddr); + asFortran << name.ToString(); + } else { // Unsupported + llvm::report_fatal_error( + "Unsupported type of OpenACC operand"); + } + } + } + }, + [&](const Fortran::parser::Name &name) { + baseAddr = getDataOperandBaseAddr(converter, builder, *name.symbol, + operandLocation); + asFortran << name.ToString(); + }}, + accObject.u); + return baseAddr; +} + +static mlir::Location +genOperandLocation(Fortran::lower::AbstractConverter &converter, + const Fortran::parser::AccObject &accObject) { + mlir::Location loc = converter.genUnknownLocation(); + std::visit(Fortran::common::visitors{ + [&](const Fortran::parser::Designator &designator) { + loc = converter.genLocation(designator.source); + }, + [&](const Fortran::parser::Name &name) { + loc = converter.genLocation(name.source); + }}, + accObject.u); + return loc; +} + +template +static Op createDataEntryOp(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value baseAddr, std::stringstream &name, + mlir::SmallVector bounds, + bool structured, mlir::acc::DataClause dataClause) { + mlir::Value varPtrPtr; + if (auto boxTy = baseAddr.getType().dyn_cast()) + baseAddr = builder.create(loc, baseAddr); + + Op op = builder.create(loc, baseAddr.getType(), baseAddr); + op.setNameAttr(builder.getStringAttr(name.str())); + op.setStructured(structured); + op.setDataClause(dataClause); + + unsigned insPos = 1; + if (varPtrPtr) + op->insertOperands(insPos++, varPtrPtr); + if (bounds.size() > 0) + op->insertOperands(insPos, bounds); + op->setAttr(Op::getOperandSegmentSizeAttr(), + builder.getDenseI32ArrayAttr( + {1, varPtrPtr ? 1 : 0, static_cast(bounds.size())})); + return op; +} + template static void genDataOperandOperations(const Fortran::parser::AccObjectList &objectList, @@ -267,162 +434,35 @@ Fortran::lower::StatementContext &stmtCtx, llvm::SmallVectorImpl &dataOperands, mlir::acc::DataClause dataClause, bool structured) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - - auto getDataOperandBaseAddr = [&](Fortran::lower::SymbolRef sym, - mlir::Location loc) -> mlir::Value { - mlir::Value symAddr = converter.getSymbolAddress(sym); - // TODO: Might need revisiting to handle for non-shared clauses - if (!symAddr) { - if (const auto *details = - sym->detailsIf()) - symAddr = converter.getSymbolAddress(details->symbol()); - } - - if (!symAddr) - llvm::report_fatal_error("could not retrieve symbol address"); - - if (auto boxTy = fir::unwrapRefType(symAddr.getType()) - .dyn_cast()) { - if (boxTy.getEleTy().isa()) - TODO(loc, "derived type"); - - // Load the box when baseAddr is a `fir.ref>` or a - // `fir.ref>` type. - if (symAddr.getType().isa()) - return builder.create(loc, symAddr); - } - return symAddr; - }; - - auto createOpAndAddOperand = [&](mlir::Value baseAddr, llvm::StringRef name, - mlir::Location loc, - llvm::SmallVector &bounds) { - if (auto boxTy = baseAddr.getType().dyn_cast()) - baseAddr = builder.create(loc, baseAddr); - - Op op = builder.create(loc, baseAddr.getType(), baseAddr); - op.setNameAttr(builder.getStringAttr(name)); - op.setStructured(structured); - op.setDataClause(dataClause); - unsigned insPos = 1; - if (bounds.size() > 0) - op->insertOperands(insPos, bounds); - op->setAttr(Op::getOperandSegmentSizeAttr(), - builder.getDenseI32ArrayAttr( - {1, 0, static_cast(bounds.size())})); - dataOperands.push_back(op.getAccPtr()); - return op; - }; - for (const auto &accObject : objectList.v) { - std::visit( - Fortran::common::visitors{ - [&](const Fortran::parser::Designator &designator) { - mlir::Location operandLocation = - converter.genLocation(designator.source); - if (auto expr{Fortran::semantics::AnalyzeExpr(semanticsContext, - designator)}) { - if ((*expr).Rank() > 0 && - Fortran::parser::Unwrap( - designator)) { - const auto *arrayElement = - Fortran::parser::Unwrap( - designator); - llvm::SmallVector bounds; - const auto *dataRef = - std::get_if(&designator.u); - mlir::Value addr; - mlir::Value baseAddr; - std::stringstream asFortran; - fir::ExtendedValue dataExv; - if (Fortran::parser::Unwrap< - Fortran::parser::StructureComponent>( - arrayElement->base)) { - auto exprBase = Fortran::semantics::AnalyzeExpr( - semanticsContext, arrayElement->base); - dataExv = converter.genExprAddr(operandLocation, *exprBase, - stmtCtx); - addr = fir::getBase(dataExv); - asFortran << (*exprBase).AsFortran(); - } else { - const Fortran::parser::Name &name = - Fortran::parser::GetLastName(*dataRef); - addr = - getDataOperandBaseAddr(*name.symbol, operandLocation); - dataExv = converter.getSymbolExtendedValue(*name.symbol); - asFortran << name.ToString(); - } - if (!arrayElement->subscripts.empty()) { - asFortran << '('; - bounds = genBoundsOps(builder, operandLocation, converter, - stmtCtx, arrayElement->subscripts, - asFortran, dataExv, addr); - } - asFortran << ')'; - createOpAndAddOperand(addr, asFortran.str(), operandLocation, - bounds); - } else if (Fortran::parser::Unwrap< - Fortran::parser::StructureComponent>( - designator)) { - fir::ExtendedValue compExv = - converter.genExprAddr(operandLocation, *expr, stmtCtx); - mlir::Value addr = fir::getBase(compExv); - llvm::SmallVector bounds; - if (fir::unwrapRefType(addr.getType()) - .isa()) - bounds = genBaseBoundsOps(builder, operandLocation, - converter, compExv, addr); - - // If the component is an allocatable or pointer the result of - // genExprAddr will be the result of a fir.box_addr operation. - // Retrieve the box so we handle it like other descriptor. - if (auto boxAddrOp = mlir::dyn_cast_or_null( - addr.getDefiningOp())) - addr = boxAddrOp.getVal(); + llvm::SmallVector bounds; + std::stringstream asFortran; + mlir::Location operandLocation = genOperandLocation(converter, accObject); + mlir::Value baseAddr = gatherDataOperandAddrAndBounds( + converter, builder, semanticsContext, stmtCtx, accObject, + operandLocation, asFortran, bounds); + Op op = createDataEntryOp(builder, operandLocation, baseAddr, asFortran, + bounds, structured, dataClause); + dataOperands.push_back(op.getAccPtr()); + } +} - createOpAndAddOperand(addr, (*expr).AsFortran(), - operandLocation, bounds); - } else { - // Scalar or full array. - if (const auto *dataRef{std::get_if( - &designator.u)}) { - const Fortran::parser::Name &name = - Fortran::parser::GetLastName(*dataRef); - fir::ExtendedValue dataExv = - converter.getSymbolExtendedValue(*name.symbol); - mlir::Value baseAddr = - getDataOperandBaseAddr(*name.symbol, operandLocation); - llvm::SmallVector bounds; - if (fir::unwrapRefType(baseAddr.getType()) - .isa()) - bounds = genBoundsOpsFromBox(builder, operandLocation, - converter, *name.symbol, - baseAddr, (*expr).Rank()); - else if (fir::unwrapRefType(baseAddr.getType()) - .isa()) - bounds = genBaseBoundsOps(builder, operandLocation, - converter, dataExv, baseAddr); - createOpAndAddOperand(baseAddr, name.ToString(), - operandLocation, bounds); - } else { // Unsupported - llvm::report_fatal_error( - "Unsupported type of OpenACC operand"); - } - } - } - }, - [&](const Fortran::parser::Name &name) { - mlir::Location operandLocation = - converter.genLocation(name.source); - mlir::Value baseAddr = - getDataOperandBaseAddr(*name.symbol, operandLocation); - llvm::SmallVector bounds; - createOpAndAddOperand(baseAddr, name.ToString(), operandLocation, - bounds); - }}, - accObject.u); +template +static void genDataExitOperantions(fir::FirOpBuilder &builder, + llvm::SmallVector operands, + bool structured, bool implicit) { + for (mlir::Value operand : operands) { + auto getDevicePtrOp = mlir::dyn_cast_or_null( + operand.getDefiningOp()); + assert(getDevicePtrOp && "acc.getdeivceptr op expected"); + mlir::Value varPtr; + if constexpr (std::is_same_v) + varPtr = getDevicePtrOp.getVarPtr(); + builder.create(getDevicePtrOp.getLoc(), getDevicePtrOp.getAccPtr(), + varPtr, getDevicePtrOp.getBounds(), + getDevicePtrOp.getDataClause(), structured, implicit, + builder.getStringAttr(*getDevicePtrOp.getName())); } } @@ -1175,8 +1215,8 @@ Fortran::lower::StatementContext &stmtCtx, const Fortran::parser::AccClauseList &accClauseList) { mlir::Value ifCond, async, waitDevnum; - llvm::SmallVector copyoutOperands, deleteOperands, - detachOperands, waitOperands, dataClauseOperands; + llvm::SmallVector waitOperands, dataClauseOperands, + copyoutOperands, deleteOperands, detachOperands; // Async and wait clause have optional values but can be present with // no value as well. When there is no value, the op has an attribute to @@ -1185,7 +1225,7 @@ bool addWaitAttr = false; bool addFinalizeAttr = false; - fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); // Lower clauses values mapped to operands. // Keep track of each group of operands separatly as clauses can appear @@ -1209,21 +1249,28 @@ copyoutClause->v; const auto &accObjectList = std::get(listWithModifier.t); - genObjectList(accObjectList, converter, semanticsContext, stmtCtx, - copyoutOperands); + genDataOperandOperations( + accObjectList, converter, semanticsContext, stmtCtx, copyoutOperands, + mlir::acc::DataClause::acc_copyout, false); } else if (const auto *deleteClause = std::get_if(&clause.u)) { - genObjectList(deleteClause->v, converter, semanticsContext, stmtCtx, - deleteOperands); + genDataOperandOperations( + deleteClause->v, converter, semanticsContext, stmtCtx, deleteOperands, + mlir::acc::DataClause::acc_delete, false); } else if (const auto *detachClause = std::get_if(&clause.u)) { - genObjectList(detachClause->v, converter, semanticsContext, stmtCtx, - detachOperands); + genDataOperandOperations( + detachClause->v, converter, semanticsContext, stmtCtx, detachOperands, + mlir::acc::DataClause::acc_detach, false); } else if (std::get_if(&clause.u)) { addFinalizeAttr = true; } } + dataClauseOperands.append(copyoutOperands); + dataClauseOperands.append(deleteOperands); + dataClauseOperands.append(detachOperands); + // Prepare the operand segment size attribute and the operands value range. llvm::SmallVector operands; llvm::SmallVector operandSegments; @@ -1231,20 +1278,25 @@ addOperand(operands, operandSegments, async); addOperand(operands, operandSegments, waitDevnum); addOperands(operands, operandSegments, waitOperands); - addOperands(operands, operandSegments, copyoutOperands); - addOperands(operands, operandSegments, deleteOperands); - addOperands(operands, operandSegments, detachOperands); + operandSegments.append({0, 0, 0}); addOperands(operands, operandSegments, dataClauseOperands); mlir::acc::ExitDataOp exitDataOp = createSimpleOp( - firOpBuilder, currentLocation, operands, operandSegments); + builder, currentLocation, operands, operandSegments); if (addAsyncAttr) - exitDataOp.setAsyncAttr(firOpBuilder.getUnitAttr()); + exitDataOp.setAsyncAttr(builder.getUnitAttr()); if (addWaitAttr) - exitDataOp.setWaitAttr(firOpBuilder.getUnitAttr()); + exitDataOp.setWaitAttr(builder.getUnitAttr()); if (addFinalizeAttr) - exitDataOp.setFinalizeAttr(firOpBuilder.getUnitAttr()); + exitDataOp.setFinalizeAttr(builder.getUnitAttr()); + + genDataExitOperantions( + builder, copyoutOperands, /*structured=*/false, /*implicit=*/false); + genDataExitOperantions( + builder, deleteOperands, /*structured=*/false, /*implicit=*/false); + genDataExitOperantions( + builder, detachOperands, /*structured=*/false, /*implicit=*/false); } template diff --git a/flang/test/Lower/OpenACC/acc-exit-data.f90 b/flang/test/Lower/OpenACC/acc-exit-data.f90 --- a/flang/test/Lower/OpenACC/acc-exit-data.f90 +++ b/flang/test/Lower/OpenACC/acc-exit-data.f90 @@ -8,59 +8,96 @@ real, pointer :: d logical :: ifCondition = .TRUE. -!CHECK: [[A:%.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Ea"} -!CHECK: [[B:%.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Eb"} -!CHECK: [[C:%.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Ec"} -!CHECK: [[D:%.*]] = fir.alloca !fir.box> {bindc_name = "d", uniq_name = "{{.*}}Ed"} +!CHECK: %[[A:.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Ea"} +!CHECK: %[[B:.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Eb"} +!CHECK: %[[C:.*]] = fir.alloca !fir.array<10x10xf32> {{{.*}}uniq_name = "{{.*}}Ec"} +!CHECK: %[[D:.*]] = fir.alloca !fir.box> {bindc_name = "d", uniq_name = "{{.*}}Ed"} !$acc exit data delete(a) -!CHECK: acc.exit_data delete([[A]] : !fir.ref>){{$}} +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) if(.true.) -!CHECK: [[IF1:%.*]] = arith.constant true -!CHECK: acc.exit_data if([[IF1]]) delete([[A]] : !fir.ref>){{$}} +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[IF1:.*]] = arith.constant true +!CHECK: acc.exit_data if(%[[IF1]]) dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) if(ifCondition) -!CHECK: [[IFCOND:%.*]] = fir.load %{{.*}} : !fir.ref> -!CHECK: [[IF2:%.*]] = fir.convert [[IFCOND]] : (!fir.logical<4>) -> i1 -!CHECK: acc.exit_data if([[IF2]]) delete([[A]] : !fir.ref>){{$}} +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[IFCOND:.*]] = fir.load %{{.*}} : !fir.ref> +!CHECK: %[[IF2:.*]] = fir.convert %[[IFCOND]] : (!fir.logical<4>) -> i1 +!CHECK: acc.exit_data if(%[[IF2]]) dataOperands(%[[DEVPTR]] : !fir.ref>){{$}} +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) delete(b) delete(c) -!CHECK: acc.exit_data delete([[A]], [[B]], [[C]] : !fir.ref>, !fir.ref>, !fir.ref>){{$}} +!CHECK: %[[DEVPTR_A:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[DEVPTR_B:.*]] = acc.getdeviceptr varPtr(%[[B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "b", structured = false} +!CHECK: %[[DEVPTR_C:.*]] = acc.getdeviceptr varPtr(%[[C]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "c", structured = false} +!CHECK: acc.exit_data dataOperands(%[[DEVPTR_A]], %[[DEVPTR_B]], %[[DEVPTR_C]] : !fir.ref>, !fir.ref>, !fir.ref>){{$}} +!CHECK: acc.delete accPtr(%[[DEVPTR_A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} +!CHECK: acc.delete accPtr(%[[DEVPTR_B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "b", structured = false} +!CHECK: acc.delete accPtr(%[[DEVPTR_C]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "c", structured = false} !$acc exit data copyout(a) delete(b) detach(d) -!CHECK: acc.exit_data copyout([[A]] : !fir.ref>) delete([[B]] : !fir.ref>) detach([[D]] : !fir.ref>>){{$}} +!CHECK: %[[DEVPTR_A:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 4 : i64, name = "a", structured = false} +!CHECK: %[[DEVPTR_B:.*]] = acc.getdeviceptr varPtr(%[[B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "b", structured = false} +!CHECK: %[[BOX_D:.*]] = fir.load %[[D]] : !fir.ref>> +!CHECK: %[[D_ADDR:.*]] = fir.box_addr %[[BOX_D]] : (!fir.box>) -> !fir.ptr +!CHECK: %[[DEVPTR_D:.*]] = acc.getdeviceptr varPtr(%[[D_ADDR]] : !fir.ptr) -> !fir.ptr {dataClause = 11 : i64, name = "d", structured = false} +!CHECK: acc.exit_data dataOperands(%[[DEVPTR_A]], %[[DEVPTR_B]], %[[DEVPTR_D]] : !fir.ref>, !fir.ref>, !fir.ptr) +!CHECK: acc.copyout accPtr(%[[DEVPTR_A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) to varPtr(%[[A]] : !fir.ref>) {name = "a", structured = false} +!CHECK: acc.delete accPtr(%[[DEVPTR_B]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "b", structured = false} +!CHECK: acc.detach accPtr(%[[DEVPTR_D]] : !fir.ptr) {name = "d", structured = false} !$acc exit data delete(a) async -!CHECK: acc.exit_data delete([[A]] : !fir.ref>) attributes {async} +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !fir.ref>) attributes {async} +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) wait -!CHECK: acc.exit_data delete([[A]] : !fir.ref>) attributes {wait} +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !fir.ref>) attributes {wait} +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) async wait -!CHECK: acc.exit_data delete([[A]] : !fir.ref>) attributes {async, wait} +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: acc.exit_data dataOperands(%[[DEVPTR]] : !fir.ref>) attributes {async, wait} +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) async(1) -!CHECK: [[ASYNC1:%.*]] = arith.constant 1 : i32 -!CHECK: acc.exit_data async([[ASYNC1]] : i32) delete([[A]] : !fir.ref>) +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[ASYNC1:.*]] = arith.constant 1 : i32 +!CHECK: acc.exit_data async(%[[ASYNC1]] : i32) dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} + !$acc exit data delete(a) async(async) -!CHECK: [[ASYNC2:%.*]] = fir.load %{{.*}} : !fir.ref -!CHECK: acc.exit_data async([[ASYNC2]] : i32) delete([[A]] : !fir.ref>) +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[ASYNC2:.*]] = fir.load %{{.*}} : !fir.ref +!CHECK: acc.exit_data async(%[[ASYNC2]] : i32) dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) wait(1) -!CHECK: [[WAIT1:%.*]] = arith.constant 1 : i32 -!CHECK: acc.exit_data wait([[WAIT1]] : i32) delete([[A]] : !fir.ref>) +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[WAIT1:.*]] = arith.constant 1 : i32 +!CHECK: acc.exit_data wait(%[[WAIT1]] : i32) dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) wait(queues: 1, 2) -!CHECK: [[WAIT2:%.*]] = arith.constant 1 : i32 -!CHECK: [[WAIT3:%.*]] = arith.constant 2 : i32 -!CHECK: acc.exit_data wait([[WAIT2]], [[WAIT3]] : i32, i32) delete([[A]] : !fir.ref>) +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[WAIT2:.*]] = arith.constant 1 : i32 +!CHECK: %[[WAIT3:.*]] = arith.constant 2 : i32 +!CHECK: acc.exit_data wait(%[[WAIT2]], %[[WAIT3]] : i32, i32) dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} !$acc exit data delete(a) wait(devnum: 1: queues: 1, 2) -!CHECK: [[WAIT4:%.*]] = arith.constant 1 : i32 -!CHECK: [[WAIT5:%.*]] = arith.constant 2 : i32 -!CHECK: [[WAIT6:%.*]] = arith.constant 1 : i32 -!CHECK: acc.exit_data wait_devnum([[WAIT6]] : i32) wait([[WAIT4]], [[WAIT5]] : i32, i32) delete([[A]] : !fir.ref>) +!CHECK: %[[DEVPTR:.*]] = acc.getdeviceptr varPtr(%[[A]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) -> !fir.ref> {dataClause = 9 : i64, name = "a", structured = false} +!CHECK: %[[WAIT4:.*]] = arith.constant 1 : i32 +!CHECK: %[[WAIT5:.*]] = arith.constant 2 : i32 +!CHECK: %[[WAIT6:.*]] = arith.constant 1 : i32 +!CHECK: acc.exit_data wait_devnum(%[[WAIT6]] : i32) wait(%[[WAIT4]], %[[WAIT5]] : i32, i32) dataOperands(%[[DEVPTR]] : !fir.ref>) +!CHECK: acc.delete accPtr(%[[DEVPTR]] : !fir.ref>) bounds(%{{.*}}, %{{.*}}) {name = "a", structured = false} end subroutine acc_exit_data diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td --- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td +++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td @@ -293,8 +293,8 @@ class OpenACC_DataExitOp traits = []> : OpenACC_Op { - let arguments = (ins Optional:$varPtr, - OpenACC_PointerLikeTypeInterface:$accPtr, + let arguments = (ins OpenACC_PointerLikeTypeInterface:$accPtr, + Optional:$varPtr, Variadic:$bounds, DefaultValuedAttr:$dataClause, DefaultValuedAttr:$structured,