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 @@ -16,6 +16,8 @@ #include "mlir/Dialect/OpenACC/OpenACC.h" namespace llvm { +template +class SmallVector; class StringRef; } @@ -23,6 +25,7 @@ class Location; class Type; class OpBuilder; +class Value; } // namespace mlir namespace fir { @@ -64,7 +67,8 @@ /// exist yet. mlir::acc::ReductionRecipeOp createOrGetReductionRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location, - mlir::Type, mlir::acc::ReductionOperator); + mlir::Type, mlir::acc::ReductionOperator, + llvm::SmallVector &); /// Get a acc.firstprivate.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 @@ -680,9 +680,24 @@ llvm_unreachable("OpenACC reduction unsupported type"); } -static mlir::Value genReductionInitValue(fir::FirOpBuilder &builder, - mlir::Location loc, mlir::Type ty, - mlir::acc::ReductionOperator op) { +/// 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 (((op.getLowerbound() && !fir::getIntIfConstant(op.getLowerbound())) || + (op.getUpperbound() && !fir::getIntIfConstant(op.getUpperbound()))) && + op.getExtent() && !fir::getIntIfConstant(op.getExtent())) + return true; + } + return false; +} + +static mlir::Value +genReductionInitValue(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type ty, mlir::acc::ReductionOperator op, + llvm::SmallVector &bounds) { if (op == mlir::acc::ReductionOperator::AccLand || op == mlir::acc::ReductionOperator::AccLor || op == mlir::acc::ReductionOperator::AccEqv || @@ -861,7 +876,8 @@ mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe( fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc, - mlir::Type ty, mlir::acc::ReductionOperator op) { + mlir::Type ty, mlir::acc::ReductionOperator op, + llvm::SmallVector &bounds) { mlir::ModuleOp mod = builder.getBlock()->getParent()->getParentOfType(); if (auto recipe = mod.lookupSymbol(recipeName)) @@ -874,7 +890,7 @@ builder.createBlock(&recipe.getInitRegion(), recipe.getInitRegion().end(), {ty}, {loc}); builder.setInsertionPointToEnd(&recipe.getInitRegion().back()); - mlir::Value initValue = genReductionInitValue(builder, loc, ty, op); + mlir::Value initValue = genReductionInitValue(builder, loc, ty, op, bounds); builder.create(loc, initValue); builder.createBlock(&recipe.getCombinerRegion(), @@ -888,20 +904,6 @@ return recipe; } -/// 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 (((op.getLowerbound() && !fir::getIntIfConstant(op.getLowerbound())) || - (op.getUpperbound() && !fir::getIntIfConstant(op.getUpperbound()))) && - op.getExtent() && !fir::getIntIfConstant(op.getExtent())) - return true; - } - return false; -} - static void genReductions(const Fortran::parser::AccObjectListWithReduction &objectList, Fortran::lower::AbstractConverter &converter, @@ -935,19 +937,19 @@ !bounds.empty())) TODO(operandLocation, "reduction with unsupported type"); + mlir::Type retTy = getTypeFromBounds(bounds, baseAddr.getType()); auto op = createDataEntryOp( builder, operandLocation, baseAddr, asFortran, bounds, - /*structured=*/true, mlir::acc::DataClause::acc_reduction, - baseAddr.getType()); + /*structured=*/true, mlir::acc::DataClause::acc_reduction, retTy); mlir::Type ty = fir::unwrapRefType(op.getAccPtr().getType()); if (!fir::isa_trivial(ty)) - ty = baseAddr.getType(); + ty = retTy; std::string recipeName = fir::getTypeAsString( ty, converter.getKindMap(), ("reduction_" + stringifyReductionOperator(mlirOp)).str()); mlir::acc::ReductionRecipeOp recipe = - Fortran::lower::createOrGetReductionRecipe(builder, recipeName, - operandLocation, ty, mlirOp); + Fortran::lower::createOrGetReductionRecipe( + builder, recipeName, operandLocation, ty, mlirOp, bounds); reductionRecipes.push_back(mlir::SymbolRefAttr::get( builder.getContext(), recipe.getSymName().str())); reductionOperands.push_back(op.getAccPtr()); diff --git a/flang/test/Lower/OpenACC/acc-reduction.f90 b/flang/test/Lower/OpenACC/acc-reduction.f90 --- a/flang/test/Lower/OpenACC/acc-reduction.f90 +++ b/flang/test/Lower/OpenACC/acc-reduction.f90 @@ -2,6 +2,26 @@ ! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s +! CHECK-LABEL: acc.reduction.recipe @reduction_add_ref_10xi32 : !fir.ref> reduction_operator init { +! CHECK: ^bb0(%{{.*}}: !fir.ref>): +! CHECK: %[[CST:.*]] = arith.constant dense<0> : vector<10xi32> +! CHECK: acc.yield %[[CST]] : vector<10xi32> +! CHECK: } combiner { +! CHECK: ^bb0(%[[ARG0:.*]]: !fir.ref>, %[[ARG1:.*]]: !fir.ref>): +! CHECK: %[[LB:.*]] = arith.constant 0 : index +! CHECK: %[[UB:.*]] = arith.constant 9 : index +! CHECK: %[[STEP:.*]] = arith.constant 1 : index +! CHECK: fir.do_loop %[[IV:.*]] = %[[LB]] to %[[UB]] step %[[STEP]] { +! CHECK: %[[COORD1:.*]] = fir.coordinate_of %[[ARG0]], %[[IV]] : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[COORD2:.*]] = fir.coordinate_of %[[ARG1]], %[[IV]] : (!fir.ref>, index) -> !fir.ref +! CHECK: %[[LOAD1:.*]] = fir.load %[[COORD1]] : !fir.ref +! CHECK: %[[LOAD2:.*]] = fir.load %[[COORD2]] : !fir.ref +! CHECK: %[[COMBINED:.*]] = arith.addi %[[LOAD1]], %[[LOAD2]] : i32 +! CHECK: fir.store %[[COMBINED]] to %[[COORD1]] : !fir.ref +! CHECK: } +! CHECK: acc.yield %[[ARG0]] : !fir.ref> +! CHECK: } + ! CHECK-LABEL: acc.reduction.recipe @reduction_mul_z32 : !fir.complex<4> reduction_operator init { ! CHECK: ^bb0(%{{.*}}: !fir.complex<4>): ! CHECK: %[[REAL:.*]] = arith.constant 1.000000e+00 : f32 @@ -804,3 +824,18 @@ ! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box>) -> !fir.ptr ! CHECK: %[[RED:.*]] = acc.reduction varPtr(%[[BOX_ADDR]] : !fir.ptr) -> !fir.ptr {name = "i"} ! CHECK: acc.parallel reduction(@reduction_add_i32 -> %[[RED]] : !fir.ptr) + +subroutine acc_reduction_add_static_slice(a) + integer :: a(100) + !$acc parallel reduction(+:a(11:20)) + !$acc end parallel +end subroutine + +! CHECK-LABEL: func.func @_QPacc_reduction_add_static_slice( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {fir.bindc_name = "a"}) +! CHECK: %[[C1:.*]] = arith.constant 1 : index +! CHECK: %[[LB:.*]] = arith.constant 10 : index +! CHECK: %[[UB:.*]] = arith.constant 19 : index +! CHECK: %[[BOUND:.*]] = acc.bounds lowerbound(%[[LB]] : index) upperbound(%[[UB]] : index) stride(%[[C1]] : index) startIdx(%[[C1]] : index) +! CHECK: %[[RED:.*]] = acc.reduction varPtr(%[[ARG0]] : !fir.ref>) bounds(%[[BOUND]]) -> !fir.ref> {name = "a(11:20)"} +! CHECK: acc.parallel reduction(@reduction_add_ref_10xi32 -> %[[RED]] : !fir.ref>)