Skip to content

Commit

Permalink
[flang][openacc] Support array with dynamic extents in firstprivate r…
Browse files Browse the repository at this point in the history
…ecipe (#69026)

Add lowering support for array with dynamic extents in the firstprivate
recipe. Generalize the lowering so static shaped arrays and array with
dynamic extents use the same path.

Some cleaning code is taken from #68836 that is not landed yet.
  • Loading branch information
clementval committed Oct 16, 2023
1 parent f74b85c commit d9568bd
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 86 deletions.
62 changes: 35 additions & 27 deletions flang/lib/Lower/OpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,20 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
mlir::OpBuilder modBuilder(mod.getBodyRegion());
auto recipe =
modBuilder.create<mlir::acc::FirstprivateRecipeOp>(loc, recipeName, ty);
llvm::SmallVector<mlir::Type> initArgsTy{ty};
llvm::SmallVector<mlir::Location> initArgsLoc{loc};
auto refTy = fir::unwrapRefType(ty);
if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(refTy)) {
if (seqTy.hasDynamicExtents()) {
mlir::Type idxTy = builder.getIndexType();
for (unsigned i = 0; i < seqTy.getDimension(); ++i) {
initArgsTy.push_back(idxTy);
initArgsLoc.push_back(loc);
}
}
}
builder.createBlock(&recipe.getInitRegion(), recipe.getInitRegion().end(),
{ty}, {loc});
initArgsTy, initArgsLoc);
builder.setInsertionPointToEnd(&recipe.getInitRegion().back());
genPrivateLikeInitRegion<mlir::acc::FirstprivateRecipeOp>(builder, recipe, ty,
loc);
Expand Down Expand Up @@ -601,32 +613,28 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
builder.create<fir::StoreOp>(loc, initValue,
recipe.getCopyRegion().front().getArgument(1));
} else if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(ty)) {
if (seqTy.hasDynamicExtents())
TODO(loc, "firstprivate recipe of array with dynamic extents");
mlir::Type idxTy = builder.getIndexType();
mlir::Type refTy = fir::ReferenceType::get(seqTy.getEleTy());
mlir::Value arraySrc = recipe.getCopyRegion().front().getArgument(0);
mlir::Value arrayDst = recipe.getCopyRegion().front().getArgument(1);
llvm::SmallVector<fir::DoLoopOp> loops;
llvm::SmallVector<mlir::Value> ivs;
for (auto ext : llvm::reverse(seqTy.getShape())) {
auto lb = builder.create<mlir::arith::ConstantOp>(
loc, idxTy, builder.getIntegerAttr(idxTy, 0));
auto ub = builder.create<mlir::arith::ConstantOp>(
loc, idxTy, builder.getIntegerAttr(idxTy, ext - 1));
auto step = builder.create<mlir::arith::ConstantOp>(
loc, idxTy, builder.getIntegerAttr(idxTy, 1));
auto loop = builder.create<fir::DoLoopOp>(loc, lb, ub, step,
/*unordered=*/false);
builder.setInsertionPointToStart(loop.getBody());
loops.push_back(loop);
ivs.push_back(loop.getInductionVar());
}
auto addr1 = builder.create<fir::CoordinateOp>(loc, refTy, arraySrc, ivs);
auto addr2 = builder.create<fir::CoordinateOp>(loc, refTy, arrayDst, ivs);
auto loadedValue = builder.create<fir::LoadOp>(loc, addr1);
builder.create<fir::StoreOp>(loc, loadedValue, addr2);
builder.setInsertionPointAfter(loops[0]);
fir::FirOpBuilder firBuilder{builder, recipe.getOperation()};
auto shape = genShapeFromBoundsOrArgs(
loc, firBuilder, seqTy, bounds, recipe.getCopyRegion().getArguments());

auto leftDeclOp = builder.create<hlfir::DeclareOp>(
loc, recipe.getCopyRegion().getArgument(0), llvm::StringRef{}, shape,
llvm::ArrayRef<mlir::Value>{}, fir::FortranVariableFlagsAttr{});
auto rightDeclOp = builder.create<hlfir::DeclareOp>(
loc, recipe.getCopyRegion().getArgument(1), llvm::StringRef{}, shape,
llvm::ArrayRef<mlir::Value>{}, fir::FortranVariableFlagsAttr{});

hlfir::DesignateOp::Subscripts triplets =
getSubscriptsFromArgs(recipe.getCopyRegion().getArguments());
auto leftEntity = hlfir::Entity{leftDeclOp.getBase()};
auto left =
genDesignateWithTriplets(firBuilder, loc, leftEntity, triplets, shape);
auto rightEntity = hlfir::Entity{rightDeclOp.getBase()};
auto right =
genDesignateWithTriplets(firBuilder, loc, rightEntity, triplets, shape);

firBuilder.create<hlfir::AssignOp>(loc, left, right);

} else if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(ty)) {
fir::FirOpBuilder firBuilder{builder, recipe.getOperation()};
llvm::SmallVector<mlir::Value> tripletArgs;
Expand Down
27 changes: 0 additions & 27 deletions flang/test/Lower/OpenACC/acc-parallel-loop.f90
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,6 @@
! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK,FIR
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,HLFIR

! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_ext10_ref_10xf32 : !fir.ref<!fir.array<10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10xf32>>):
! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<10xf32>
! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<10xf32>>, %[[DST:.*]]: !fir.ref<!fir.array<10xf32>>):
! CHECK: %[[LB0:.*]] = arith.constant 0 : index
! CHECK: %[[UB0:.*]] = arith.constant 9 : index
! CHECK: %[[STEP0:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[IV0:.*]] = %[[LB0]] to %[[UB0]] step %[[STEP0]] {
! CHECK: %[[COORD0:.*]] = fir.coordinate_of %[[SRC]], %[[IV0]] : (!fir.ref<!fir.array<10xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[COORD1:.*]] = fir.coordinate_of %[[DST]], %[[IV0]] : (!fir.ref<!fir.array<10xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[LOAD:.*]] = fir.load %[[COORD0]] : !fir.ref<f32>
! CHECK: fir.store %[[LOAD]] to %[[COORD1]] : !fir.ref<f32>
! CHECK: }
! CHECK: acc.terminator
! CHECK: }

! CHECK-LABEL: acc.private.recipe @privatization_ref_10xf32 : !fir.ref<!fir.array<10xf32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.ref<!fir.array<10xf32>>):
! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! HLFIR: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<10xf32>>
! CHECK: }

! CHECK-LABEL: func.func @_QPacc_parallel_loop()

subroutine acc_parallel_loop
Expand Down
60 changes: 41 additions & 19 deletions flang/test/Lower/OpenACC/acc-private.f90
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK,FIR
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,HLFIR

! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_UxUx2xi32 : !fir.ref<!fir.array<?x?x2xi32>> init {
! CHECK: ^bb0(%[[ARG0:.*]]: !fir.ref<!fir.array<?x?x2xi32>>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index):
! HLFIR: %[[SHAPE:.*]] = fir.shape %[[ARG1]], %[[ARG2]], %[[ARG3]] : (index, index, index) -> !fir.shape<3>
! HLFIR: %[[TEMP:.*]] = fir.alloca !fir.array<?x?x2xi32>, %[[ARG1]], %[[ARG2]], %[[ARG3]]
! HLFIR: %[[DECL:.*]]:2 = hlfir.declare %[[TEMP]](%[[SHAPE]]) {uniq_name = "acc.private.init"} : (!fir.ref<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x2xi32>>, !fir.ref<!fir.array<?x?x2xi32>>)
! HLFIR: acc.yield %[[DECL]]#0 : !fir.box<!fir.array<?x?x2xi32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<?x?x2xi32>>, %[[DST:.*]]: !fir.ref<!fir.array<?x?x2xi32>>, %[[LB0:.*]]: index, %[[UB0:.*]]: index, %[[STEP0:.*]]: index, %[[LB1:.*]]: index, %[[UB1:.*]]: index, %[[STEP1:.*]]: index, %[[LB2:.*]]: index, %[[UB2:.*]]: index, %[[STEP2:.*]]: index):
! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}}, %{{.*}}, %{{.*}} : (index, index, index) -> !fir.shape<3>
! HLFIR: %[[DECL_SRC:.*]]:2 = hlfir.declare %[[SRC]](%[[SHAPE]]) {uniq_name = ""} : (!fir.ref<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x2xi32>>, !fir.ref<!fir.array<?x?x2xi32>>)
! HLFIR: %[[DECL_DST:.*]]:2 = hlfir.declare %[[DST]](%[[SHAPE]]) {uniq_name = ""} : (!fir.ref<!fir.array<?x?x2xi32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x2xi32>>, !fir.ref<!fir.array<?x?x2xi32>>)
! HLFIR: %[[DES_SRC:.*]] = hlfir.designate %[[DECL_SRC]]#0 (%[[LB0]]:%[[UB0]]:%[[STEP0]], %[[LB1]]:%[[UB1]]:%[[STEP1]], %[[LB2]]:%[[UB2]]:%[[STEP2]]) shape %[[SHAPE]] : (!fir.box<!fir.array<?x?x2xi32>>, index, index, index, index, index, index, index, index, index, !fir.shape<3>) -> !fir.box<!fir.array<?x?x2xi32>>
! HLFIR: %[[DES_DST:.*]] = hlfir.designate %[[DECL_DST]]#0 (%[[LB0]]:%[[UB0]]:%[[STEP0]], %[[LB1]]:%[[UB1]]:%[[STEP1]], %[[LB2]]:%[[UB2]]:%[[STEP2]]) shape %[[SHAPE]] : (!fir.box<!fir.array<?x?x2xi32>>, index, index, index, index, index, index, index, index, index, !fir.shape<3>) -> !fir.box<!fir.array<?x?x2xi32>>
! HLFIR: hlfir.assign %[[DES_SRC]] to %[[DES_DST]] : !fir.box<!fir.array<?x?x2xi32>>, !fir.box<!fir.array<?x?x2xi32>>
! HLFIR: acc.terminator
! CHECK: }

! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_lb4.ub9_box_Uxi32 : !fir.box<!fir.array<?xi32>> init {
! CHECK: ^bb0(%{{.*}}: !fir.box<!fir.array<?xi32>>):
! CHECK: } copy {
Expand Down Expand Up @@ -87,16 +104,12 @@
! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<50xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<50xf32>>, %[[DST:.*]]: !fir.ref<!fir.array<50xf32>>):
! CHECK: %[[LB0:.*]] = arith.constant 0 : index
! CHECK: %[[UB0:.*]] = arith.constant 49 : index
! CHECK: %[[STEP0:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[IV0:.*]] = %[[LB0]] to %[[UB0]] step %[[STEP0]] {
! CHECK: %[[COORD0:.*]] = fir.coordinate_of %[[SRC]], %[[IV0]] : (!fir.ref<!fir.array<50xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[COORD1:.*]] = fir.coordinate_of %[[DST]], %[[IV0]] : (!fir.ref<!fir.array<50xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[VALUE:.*]] = fir.load %[[COORD0]] : !fir.ref<f32>
! CHECK: fir.store %[[VALUE]] to %[[COORD1]] : !fir.ref<f32>
! CHECK: }
! CHECK: acc.terminator
! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! HLFIR: %[[DECL_SRC:.*]]:2 = hlfir.declare %[[SRC]](%[[SHAPE]]) {uniq_name = ""} : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>)
! HLFIR: %[[DECL_DST:.*]]:2 = hlfir.declare %[[DST]](%[[SHAPE]]) {uniq_name = ""} : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>)
! HLFIR: %[[DES_SRC:.*]] = hlfir.designate %[[DECL_SRC]]#0 shape %[[SHAPE:.*]] : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! HLFIR: %[[DES_DST:.*]] = hlfir.designate %[[DECL_DST]]#0 shape %[[SHAPE:.*]] : (!fir.ref<!fir.array<50xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<50xf32>>
! HLFIR: hlfir.assign %[[DES_SRC]] to %[[DES_DST]] : !fir.ref<!fir.array<50xf32>>, !fir.ref<!fir.array<50xf32>>
! CHECK: }

! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_section_ext100_ref_100xf32 : !fir.ref<!fir.array<100xf32>> init {
Expand All @@ -107,15 +120,12 @@
! HLFIR: acc.yield %[[DECLARE]]#0 : !fir.ref<!fir.array<100xf32>>
! CHECK: } copy {
! CHECK: ^bb0(%[[SRC:.*]]: !fir.ref<!fir.array<100xf32>>, %[[DST:.*]]: !fir.ref<!fir.array<100xf32>>):
! CHECK: %[[LB0:.*]] = arith.constant 0 : index
! CHECK: %[[UB0:.*]] = arith.constant 99 : index
! CHECK: %[[STEP1:.*]] = arith.constant 1 : index
! CHECK: fir.do_loop %[[IV0:.*]] = %c0 to %c99 step %c1 {
! CHECK: %[[COORD0:.*]] = fir.coordinate_of %[[SRC]], %[[IV0]] : (!fir.ref<!fir.array<100xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[COORD1:.*]] = fir.coordinate_of %[[DST]], %[[IV0]] : (!fir.ref<!fir.array<100xf32>>, index) -> !fir.ref<f32>
! CHECK: %[[VALUE:.*]] = fir.load %[[COORD0]] : !fir.ref<f32>
! CHECK: fir.store %[[VALUE]] to %[[COORD1]] : !fir.ref<f32>
! CHECK: }
! HLFIR: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! HLFIR: %[[DECL_SRC:.*]]:2 = hlfir.declare %[[SRC]](%[[SHAPE]]) {uniq_name = ""} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
! HLFIR: %[[DECL_DST:.*]]:2 = hlfir.declare %[[DST]](%[[SHAPE]]) {uniq_name = ""} : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>)
! HLFIR: %[[DES_SRC:.*]] = hlfir.designate %[[DECL_SRC]]#0 shape %[[SHAPE]] : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<100xf32>>
! HLFIR: %[[DES_DST:.*]] = hlfir.designate %[[DECL_DST]]#0 shape %[[SHAPE]] : (!fir.ref<!fir.array<100xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<100xf32>>
! HLFIR: hlfir.assign %[[DES_SRC]] to %[[DES_DST]] : !fir.ref<!fir.array<100xf32>>, !fir.ref<!fir.array<100xf32>>
! CHECK: acc.terminator
! CHECK: }

Expand Down Expand Up @@ -337,3 +347,15 @@ subroutine acc_firstprivate_assumed_shape_with_section(a, n)
a(i) = i
end do
end subroutine

subroutine acc_firstprivate_dynamic_extent(a, n)
integer :: n, i
integer :: a(n, n, 2)

!$acc parallel loop firstprivate(a)
do i = 1, n
a(i, i, 1) = i
end do
end subroutine

! CHECK: acc.parallel firstprivate(@firstprivatization_ref_UxUx2xi32 -> %{{.*}} : !fir.ref<!fir.array<?x?x2xi32>>)
2 changes: 1 addition & 1 deletion mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ LogicalResult acc::PrivateRecipeOp::verifyRegions() {
LogicalResult acc::FirstprivateRecipeOp::verifyRegions() {
if (failed(verifyInitLikeSingleArgRegion(*this, getInitRegion(),
"privatization", "init", getType(),
/*verifyYield=*/true)))
/*verifyYield=*/false)))
return failure();

if (getCopyRegion().empty())
Expand Down
12 changes: 0 additions & 12 deletions mlir/test/Dialect/OpenACC/invalid.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -312,18 +312,6 @@ acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {

// -----

// expected-error@+1 {{expects init region to yield a value of the privatization type}}
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<f32> init {
^bb0(%arg0 : !llvm.ptr<f32>):
%c1 = arith.constant 1 : i32
%c0 = arith.constant 0 : i32
%0 = llvm.alloca %c1 x i32 : (i32) -> !llvm.ptr<i32>
llvm.store %c0, %0 : !llvm.ptr<i32>
acc.yield %0 : !llvm.ptr<i32>
} copy {}

// -----

// expected-error@+1 {{expects non-empty copy region}}
acc.firstprivate.recipe @privatization_i32 : !llvm.ptr<i32> init {
^bb0(%arg0 : !llvm.ptr<i32>):
Expand Down

0 comments on commit d9568bd

Please sign in to comment.