diff --git a/flang/include/flang/Lower/OpenACC.h b/flang/include/flang/Lower/OpenACC.h --- a/flang/include/flang/Lower/OpenACC.h +++ b/flang/include/flang/Lower/OpenACC.h @@ -59,9 +59,9 @@ /// Get a acc.private.recipe op for the given type or create it if it does not /// exist yet. -mlir::acc::PrivateRecipeOp createOrGetPrivateRecipe(mlir::OpBuilder &, - llvm::StringRef, - mlir::Location, mlir::Type); +mlir::acc::PrivateRecipeOp +createOrGetPrivateRecipe(mlir::OpBuilder &, llvm::StringRef, mlir::Location, + mlir::Type, llvm::SmallVector &); /// Get a acc.reduction.recipe op for the given type or create it if it does not /// exist yet. 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 @@ -421,19 +421,55 @@ retVal = builder.create(loc, refTy.getEleTy()); else if (auto seqTy = mlir::dyn_cast_or_null(refTy.getEleTy())) { - if (seqTy.hasDynamicExtents()) - TODO(loc, "private recipe of array with dynamic extents"); - if (fir::isa_trivial(seqTy.getEleTy())) + if (!fir::isa_trivial(seqTy.getEleTy())) + llvm::report_fatal_error("unsupported type"); + if (seqTy.hasDynamicExtents()) { + mlir::Block* block = builder.getBlock(); + assert(seqTy.getDimension() == (block->getNumArguments() - 1) && + "expect dynamic extents passed as block arguments"); + llvm::SmallVector extents; + for (unsigned i = 1; i < block->getNumArguments(); ++i) + extents.push_back(block->getArgument(i)); + retVal = builder.create(loc, seqTy, + /*unique_name=*/llvm::StringRef{}, ".private_init", + /*pinned=*/false, mlir::ValueRange(), extents, llvm::ArrayRef()); + + } else { retVal = builder.create(loc, seqTy); + } } } builder.create(loc, retVal); } +/// Check if the DataBoundsOp is a constant bound (lb and ub are constants or +/// extent is a constant). +bool isConstantBound(mlir::acc::DataBoundsOp &op) { + if (op.getLowerbound() && fir::getIntIfConstant(op.getLowerbound()) && + op.getUpperbound() && fir::getIntIfConstant(op.getUpperbound())) + return true; + if (op.getExtent() && fir::getIntIfConstant(op.getExtent())) + return true; + return false; +} + +/// Determine if the bounds represent a dynamic shape. +bool hasDynamicShape(llvm::SmallVector &bounds) { + if (bounds.empty()) + return false; + for (auto b : bounds) { + auto op = mlir::dyn_cast(b.getDefiningOp()); + if (!isConstantBound(op)) + return true; + } + return false; +} + mlir::acc::PrivateRecipeOp Fortran::lower::createOrGetPrivateRecipe(mlir::OpBuilder &builder, llvm::StringRef recipeName, - mlir::Location loc, mlir::Type ty) { + mlir::Location loc, mlir::Type ty, + llvm::SmallVector &bounds) { mlir::ModuleOp mod = builder.getBlock()->getParent()->getParentOfType(); if (auto recipe = mod.lookupSymbol(recipeName)) @@ -443,8 +479,18 @@ mlir::OpBuilder modBuilder(mod.getBodyRegion()); auto recipe = modBuilder.create(loc, recipeName, ty); + llvm::SmallVector argTypes; + llvm::SmallVector argLocs; + argTypes.push_back(ty); + argLocs.push_back(loc); + if (hasDynamicShape(bounds)) { + for (unsigned i; i < bounds.size(); ++i) { + argTypes.push_back(builder.getIndexType()); + argLocs.push_back(loc); + } + } builder.createBlock(&recipe.getInitRegion(), recipe.getInitRegion().end(), - {ty}, {loc}); + argTypes, argLocs); builder.setInsertionPointToEnd(&recipe.getInitRegion().back()); genPrivateLikeInitRegion(builder, recipe, ty, loc); @@ -575,7 +621,8 @@ std::string recipeName = fir::getTypeAsString(retTy, converter.getKindMap(), "privatization"); recipe = Fortran::lower::createOrGetPrivateRecipe(builder, recipeName, - operandLocation, retTy); + operandLocation, retTy, + bounds); auto op = createDataEntryOp( builder, operandLocation, baseAddr, asFortran, bounds, true, mlir::acc::DataClause::acc_private, retTy); @@ -680,29 +727,6 @@ llvm_unreachable("OpenACC reduction unsupported type"); } -/// Check if the DataBoundsOp is a constant bound (lb and ub are constants or -/// extent is a constant). -bool isConstantBound(mlir::acc::DataBoundsOp &op) { - if (op.getLowerbound() && fir::getIntIfConstant(op.getLowerbound()) && - op.getUpperbound() && fir::getIntIfConstant(op.getUpperbound())) - return true; - if (op.getExtent() && fir::getIntIfConstant(op.getExtent())) - return true; - return false; -} - -/// Determine if the bounds represent a dynamic shape. -bool hasDynamicShape(llvm::SmallVector &bounds) { - if (bounds.empty()) - return false; - for (auto b : bounds) { - auto op = mlir::dyn_cast(b.getDefiningOp()); - if (!isConstantBound(op)) - return true; - } - return false; -} - static mlir::Value genScalarReductionValue(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type ty, mlir::acc::ReductionOperator op) { diff --git a/flang/test/Lower/OpenACC/acc-private.f90 b/flang/test/Lower/OpenACC/acc-private.f90 --- a/flang/test/Lower/OpenACC/acc-private.f90 +++ b/flang/test/Lower/OpenACC/acc-private.f90 @@ -2,6 +2,12 @@ ! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s +! CHECK-LABEL: acc.private.recipe @"privatization_ref_?xf32" : !fir.ref> init { +! CHECK: ^bb0(%{{.*}}: !fir.ref>, %[[EXT:.*]]: index): +! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array, %[[EXT]] {bindc_name = ".private_init"} +! CHECK: acc.yield %[[ALLOCA]] : !fir.ref> +! CHECK: } + ! CHECK-LABEL: acc.firstprivate.recipe @firstprivatization_ref_50xf32 : !fir.ref> init { ! CHECK: ^bb0(%{{.*}}: !fir.ref>): ! CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<50xf32> @@ -71,6 +77,7 @@ integer :: i, c integer, parameter :: n = 100 real, dimension(n) :: a, b + integer :: x,y ! CHECK: %[[B:.*]] = fir.address_of(@_QFEb) : !fir.ref> ! CHECK: %[[C:.*]] = fir.alloca i32 {bindc_name = "c", uniq_name = "_QFEc"} @@ -149,4 +156,9 @@ ! CHECK: %[[FP_B:.*]] = acc.firstprivate varPtr(%[[B]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "b(51:100)"} ! CHECK: acc.parallel firstprivate(@firstprivatization_ref_50xf32 -> %[[FP_B]] : !fir.ref>) + !$acc parallel loop private(a(x:y)) + DO i = 1, n + c = i + a(i) = b(i) + c + END DO end program