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 @@ -15,6 +15,7 @@ #include "flang/Lower/Bridge.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/StatementContext.h" +#include "flang/Lower/Support/Utils.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/Todo.h" @@ -100,6 +101,70 @@ } } +static llvm::SmallVector +genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, + Fortran::lower::AbstractConverter &converter, + const std::list &subscripts, + std::stringstream &asFortran, const Fortran::parser::Name &name) { + int dimension = 0; + mlir::Type i64Ty = builder.getI64Type(); + mlir::Type boundTy = builder.getType(); + llvm::SmallVector bounds; + for (const auto &subscript : subscripts) { + if (const auto *triplet{ + std::get_if(&subscript.u)}) { + if (dimension != 0) + asFortran << ','; + mlir::Value lbound, ubound, extent; + std::optional lval, uval; + const auto &lower{std::get<0>(triplet->t)}; + if (lower) { + lval = Fortran::semantics::GetIntValue(lower); + if (lval) { + lbound = builder.createIntegerConstant(loc, i64Ty, *lval); + asFortran << *lval; + } else { + TODO(loc, "non constant lower bound in array section"); + } + } + asFortran << ':'; + const auto &upper{std::get<1>(triplet->t)}; + if (upper) { + uval = Fortran::semantics::GetIntValue(upper); + if (uval) { + ubound = builder.createIntegerConstant(loc, i64Ty, *uval); + asFortran << *uval; + } else { + TODO(loc, "non constant upper bound in array section"); + } + } + if (lower && upper) { + if (lval && uval && *uval < *lval) { + mlir::emitError(loc, "zero sized array section"); + break; + } else if (std::get<2>(triplet->t)) { + const auto &strideExpr{std::get<2>(triplet->t)}; + if (strideExpr) { + mlir::emitError(loc, "stride cannot be specified on " + "an OpenACC array section"); + break; + } + } + } + if (!ubound) { + fir::ExtendedValue x = converter.getSymbolExtendedValue(*name.symbol); + extent = fir::factory::readExtent(builder, loc, x, dimension); + } + mlir::Value empty; + mlir::Value bound = builder.create( + loc, boundTy, lbound, ubound, extent, empty, false, empty); + bounds.push_back(bound); + ++dimension; + } + } + return bounds; +} + template static void genDataOperandOperations(const Fortran::parser::AccObjectList &objectList, @@ -112,7 +177,8 @@ fir::FirOpBuilder &builder = converter.getFirOpBuilder(); auto createOpAndAddOperand = [&](Fortran::lower::SymbolRef sym, - llvm::StringRef name, mlir::Location loc) { + llvm::StringRef name, + mlir::Location loc) -> Op { mlir::Value symAddr = converter.getSymbolAddress(sym); // TODO: Might need revisiting to handle for non-shared clauses if (!symAddr) { @@ -124,6 +190,8 @@ if (!symAddr) llvm::report_fatal_error("could not retrieve symbol address"); + if (symAddr.getType().isa()) + TODO(loc, "data operand operation creation for box types"); Op op = builder.create(loc, symAddr.getType(), symAddr); op.setNameAttr(builder.getStringAttr(name)); op.setStructured(structured); @@ -131,6 +199,7 @@ op->setAttr(Op::getOperandSegmentSizeAttr(), builder.getDenseI32ArrayAttr({1, 0, 0})); dataOperands.push_back(op.getAccPtr()); + return op; }; for (const auto &accObject : objectList.v) { @@ -144,7 +213,29 @@ if ((*expr).Rank() > 0 && Fortran::parser::Unwrap( designator)) { - TODO(operandLocation, "OpenACC array section data operand"); + const auto *arrayElement = + Fortran::parser::Unwrap( + designator); + llvm::SmallVector bounds; + const auto *dataRef = + std::get_if(&designator.u); + const Fortran::parser::Name &name = + Fortran::parser::GetLastName(*dataRef); + std::stringstream asFortran; + asFortran << name.ToString(); + if (!arrayElement->subscripts.empty()) { + asFortran << '('; + bounds = + genBoundsOps(builder, operandLocation, converter, + arrayElement->subscripts, asFortran, name); + } + asFortran << ')'; + Op op = createOpAndAddOperand(*name.symbol, asFortran.str(), + operandLocation); + op->insertOperands(1, bounds); + op->setAttr(Op::getOperandSegmentSizeAttr(), + builder.getDenseI32ArrayAttr( + {1, 0, static_cast(bounds.size())})); } else if (Fortran::parser::Unwrap< Fortran::parser::StructureComponent>( designator)) { diff --git a/flang/test/Lower/OpenACC/acc-enter-data.f90 b/flang/test/Lower/OpenACC/acc-enter-data.f90 --- a/flang/test/Lower/OpenACC/acc-enter-data.f90 +++ b/flang/test/Lower/OpenACC/acc-enter-data.f90 @@ -8,6 +8,7 @@ real, pointer :: d logical :: ifCondition = .TRUE. +!CHECK: %[[EXTENT_C10:.*]] = arith.constant 10 : index !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"} @@ -86,4 +87,48 @@ !CHECK: %[[WAIT6:.*]] = arith.constant 1 : i32 !CHECK: acc.enter_data wait_devnum(%[[WAIT6]] : i32) wait(%[[WAIT4]], %[[WAIT5]] : i32, i32) dataOperands(%[[CREATE_A]] : !fir.ref>) + !$acc enter data copyin(a(1:10,1:5)) +!CHECK: %[[LB1:.*]] = arith.constant 1 : i64 +!CHECK: %[[UB1:.*]] = arith.constant 10 : i64 +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB1]] : i64) upperbound(%[[UB1]] : i64) +!CHECK: %[[LB2:.*]] = arith.constant 1 : i64 +!CHECK: %[[UB2:.*]] = arith.constant 5 : i64 +!CHECK: %[[BOUND2:.*]] = acc.bounds lowerbound(%[[LB2]] : i64) upperbound(%[[UB2]] : i64) +!CHECK: %[[COPYIN_A:.*]] = acc.copyin varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref> {name = "a(1:10,1:5)", structured = false} +!CHECK: acc.enter_data dataOperands(%[[COPYIN_A]] : !fir.ref>) + + !$acc enter data copyin(a(1:,1:5)) +!CHECK: %[[LB1:.*]] = arith.constant 1 : i64 +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB1]] : i64) extent(%[[EXTENT_C10]] : index) +!CHECK: %[[LB2:.*]] = arith.constant 1 : i64 +!CHECK: %[[UB2:.*]] = arith.constant 5 : i64 +!CHECK: %[[BOUND2:.*]] = acc.bounds lowerbound(%[[LB2]] : i64) upperbound(%[[UB2]] : i64) +!CHECK: %[[COPYIN_A:.*]] = acc.copyin varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref> {name = "a(1:,1:5)", structured = false} +!CHECK: acc.enter_data dataOperands(%[[COPYIN_A]] : !fir.ref>) + + !$acc enter data copyin(a(:10,1:5)) +!CHECK: %[[UB1:.*]] = arith.constant 10 : i64 +!CHECK: %[[BOUND1:.*]] = acc.bounds upperbound(%[[UB1]] : i64) +!CHECK: %[[LB2:.*]] = arith.constant 1 : i64 +!CHECK: %[[UB2:.*]] = arith.constant 5 : i64 +!CHECK: %[[BOUND2:.*]] = acc.bounds lowerbound(%[[LB2]] : i64) upperbound(%[[UB2]] : i64) +!CHECK: %[[COPYIN_A:.*]] = acc.copyin varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref> {name = "a(:10,1:5)", structured = false} +!CHECK: acc.enter_data dataOperands(%[[COPYIN_A]] : !fir.ref>) + end subroutine acc_enter_data + + +subroutine acc_enter_data_dummy(a) + real :: a(1:10) + +!CHECK-LABEL: func.func @_QPacc_enter_data_dummy +!CHECK-SAME: %[[A:.*]]: !fir.ref> {fir.bindc_name = "a"} + + !$acc enter data create(a(5:10)) +!CHECK: %[[LB1:.*]] = arith.constant 5 : i64 +!CHECK: %[[UB1:.*]] = arith.constant 10 : i64 +!CHECK: %[[BOUND1:.*]] = acc.bounds lowerbound(%[[LB1]] : i64) upperbound(%[[UB1]] : i64) +!CHECK: %[[CREATE1:.*]] = acc.create varPtr(%[[A]] : !fir.ref>) bounds(%[[BOUND1]]) -> !fir.ref> {name = "a(5:10)", structured = false} +!CHECK: acc.enter_data dataOperands(%[[CREATE1]] : !fir.ref>) + +end subroutine