Skip to content

Commit

Permalink
[flang][openacc] Support array section with constant lb or ub for dat…
Browse files Browse the repository at this point in the history
…a operand

Add support for array section with constant lower or upper bound.
The current lowering will trigger a TODO when the array is assumed size
or if the lower or upper bound is a variable.

Depends on D148721

Reviewed By: razvanlupusoru, jeanPerier

Differential Revision: https://reviews.llvm.org/D148748
  • Loading branch information
clementval committed Apr 20, 2023
1 parent c1ee219 commit dc55d47
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 2 deletions.
95 changes: 93 additions & 2 deletions flang/lib/Lower/OpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -100,6 +101,70 @@ genObjectList(const Fortran::parser::AccObjectList &objectList,
}
}

static llvm::SmallVector<mlir::Value>
genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc,
Fortran::lower::AbstractConverter &converter,
const std::list<Fortran::parser::SectionSubscript> &subscripts,
std::stringstream &asFortran, const Fortran::parser::Name &name) {
int dimension = 0;
mlir::Type i64Ty = builder.getI64Type();
mlir::Type boundTy = builder.getType<mlir::acc::DataBoundsType>();
llvm::SmallVector<mlir::Value> bounds;
for (const auto &subscript : subscripts) {
if (const auto *triplet{
std::get_if<Fortran::parser::SubscriptTriplet>(&subscript.u)}) {
if (dimension != 0)
asFortran << ',';
mlir::Value lbound, ubound, extent;
std::optional<std::int64_t> 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<mlir::acc::DataBoundsOp>(
loc, boundTy, lbound, ubound, extent, empty, false, empty);
bounds.push_back(bound);
++dimension;
}
}
return bounds;
}

template <typename Op>
static void
genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
Expand All @@ -112,7 +177,8 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
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) {
Expand All @@ -124,13 +190,16 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
if (!symAddr)
llvm::report_fatal_error("could not retrieve symbol address");

if (symAddr.getType().isa<fir::BaseBoxType>())
TODO(loc, "data operand operation creation for box types");
Op op = builder.create<Op>(loc, symAddr.getType(), symAddr);
op.setNameAttr(builder.getStringAttr(name));
op.setStructured(structured);
op.setDataClause(dataClause);
op->setAttr(Op::getOperandSegmentSizeAttr(),
builder.getDenseI32ArrayAttr({1, 0, 0}));
dataOperands.push_back(op.getAccPtr());
return op;
};

for (const auto &accObject : objectList.v) {
Expand All @@ -144,7 +213,29 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList,
if ((*expr).Rank() > 0 &&
Fortran::parser::Unwrap<Fortran::parser::ArrayElement>(
designator)) {
TODO(operandLocation, "OpenACC array section data operand");
const auto *arrayElement =
Fortran::parser::Unwrap<Fortran::parser::ArrayElement>(
designator);
llvm::SmallVector<mlir::Value> bounds;
const auto *dataRef =
std::get_if<Fortran::parser::DataRef>(&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<int32_t>(bounds.size())}));
} else if (Fortran::parser::Unwrap<
Fortran::parser::StructureComponent>(
designator)) {
Expand Down
45 changes: 45 additions & 0 deletions flang/test/Lower/OpenACC/acc-enter-data.f90
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ subroutine acc_enter_data
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"}
Expand Down Expand Up @@ -86,4 +87,48 @@ subroutine acc_enter_data
!CHECK: %[[WAIT6:.*]] = arith.constant 1 : i32
!CHECK: acc.enter_data wait_devnum(%[[WAIT6]] : i32) wait(%[[WAIT4]], %[[WAIT5]] : i32, i32) dataOperands(%[[CREATE_A]] : !fir.ref<!fir.array<10x10xf32>>)

!$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<!fir.array<10x10xf32>>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref<!fir.array<10x10xf32>> {name = "a(1:10,1:5)", structured = false}
!CHECK: acc.enter_data dataOperands(%[[COPYIN_A]] : !fir.ref<!fir.array<10x10xf32>>)

!$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<!fir.array<10x10xf32>>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref<!fir.array<10x10xf32>> {name = "a(1:,1:5)", structured = false}
!CHECK: acc.enter_data dataOperands(%[[COPYIN_A]] : !fir.ref<!fir.array<10x10xf32>>)

!$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<!fir.array<10x10xf32>>) bounds(%[[BOUND1]], %[[BOUND2]]) -> !fir.ref<!fir.array<10x10xf32>> {name = "a(:10,1:5)", structured = false}
!CHECK: acc.enter_data dataOperands(%[[COPYIN_A]] : !fir.ref<!fir.array<10x10xf32>>)

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.array<10xf32>> {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<!fir.array<10xf32>>) bounds(%[[BOUND1]]) -> !fir.ref<!fir.array<10xf32>> {name = "a(5:10)", structured = false}
!CHECK: acc.enter_data dataOperands(%[[CREATE1]] : !fir.ref<!fir.array<10xf32>>)

end subroutine

0 comments on commit dc55d47

Please sign in to comment.