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 @@ -25,6 +25,10 @@ class OpBuilder; } // namespace mlir +namespace fir { +class FirOpBuilder; +} + namespace Fortran { namespace parser { struct OpenACCConstruct; @@ -59,7 +63,7 @@ /// Get a acc.reduction.recipe op for the given type or create it if it does not /// exist yet. mlir::acc::ReductionRecipeOp -createOrGetReductionRecipe(mlir::OpBuilder &, llvm::StringRef, mlir::Location, +createOrGetReductionRecipe(fir::FirOpBuilder &, llvm::StringRef, mlir::Location, mlir::Type, mlir::acc::ReductionOperator); /// Get a acc.firstprivate.recipe op for the given type or create it if it does 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 @@ -18,6 +18,7 @@ #include "flang/Lower/Support/Utils.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/IntrinsicCall.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/expression.h" @@ -526,27 +527,45 @@ llvm_unreachable("unexpected reduction operator"); } -static mlir::Value genReductionInitValue(mlir::OpBuilder &builder, +static mlir::Value genReductionInitValue(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type ty, mlir::acc::ReductionOperator op) { if (op != mlir::acc::ReductionOperator::AccAdd && - op != mlir::acc::ReductionOperator::AccMul) + op != mlir::acc::ReductionOperator::AccMul && + op != mlir::acc::ReductionOperator::AccMin) TODO(loc, "reduction operator"); - // 0 for +, ior, ieor - // 1 for * - unsigned initValue = op == mlir::acc::ReductionOperator::AccMul ? 1 : 0; - - if (ty.isIntOrIndex()) - return builder.create( - loc, ty, builder.getIntegerAttr(ty, initValue)); - if (mlir::isa(ty)) - return builder.create( - loc, ty, builder.getFloatAttr(ty, initValue)); + // min -> largest + if (op == mlir::acc::ReductionOperator::AccMin) { + if (ty.isIntOrIndex()) { + unsigned bits = ty.getIntOrFloatBitWidth(); + return builder.create( + loc, ty, + builder.getIntegerAttr( + ty, llvm::APInt::getSignedMaxValue(bits).getSExtValue())); + } + if (auto floatTy = mlir::dyn_cast_or_null(ty)) { + const llvm::fltSemantics &sem = floatTy.getFloatSemantics(); + return builder.create( + loc, ty, + builder.getFloatAttr( + ty, llvm::APFloat::getLargest(sem, /*negative=*/false))); + } + } else { + // 0 for +, ior, ieor + // 1 for * + int64_t initValue = op == mlir::acc::ReductionOperator::AccMul ? 1 : 0; + if (ty.isIntOrIndex()) + return builder.create( + loc, ty, builder.getIntegerAttr(ty, initValue)); + if (mlir::isa(ty)) + return builder.create( + loc, ty, builder.getFloatAttr(ty, initValue)); + } TODO(loc, "reduction type"); } -static mlir::Value genCombiner(mlir::OpBuilder &builder, mlir::Location loc, +static mlir::Value genCombiner(fir::FirOpBuilder &builder, mlir::Location loc, mlir::acc::ReductionOperator op, mlir::Type ty, mlir::Value value1, mlir::Value value2) { if (op == mlir::acc::ReductionOperator::AccAdd) { @@ -564,11 +583,15 @@ return builder.create(loc, value1, value2); TODO(loc, "reduction mul type"); } + + if (op == mlir::acc::ReductionOperator::AccMin) + return fir::genMin(builder, loc, {value1, value2}); + TODO(loc, "reduction operator"); } mlir::acc::ReductionRecipeOp Fortran::lower::createOrGetReductionRecipe( - mlir::OpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc, + fir::FirOpBuilder &builder, llvm::StringRef recipeName, mlir::Location loc, mlir::Type ty, mlir::acc::ReductionOperator op) { mlir::ModuleOp mod = builder.getBlock()->getParent()->getParentOfType(); 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,28 @@ ! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s +! CHECK-LABEL: acc.reduction.recipe @reduction_min_f32 : f32 reduction_operator init { +! CHECK: ^bb0(%{{.*}}: f32): +! CHECK: %[[INIT:.*]] = arith.constant 3.40282347E+38 : f32 +! CHECK: acc.yield %[[INIT]] : f32 +! CHECK: } combiner { +! CHECK: ^bb0(%[[ARG0:.*]]: f32, %[[ARG1:.*]]: f32): +! CHECK: %[[CMP:.*]] = arith.cmpf olt, %[[ARG0]], %[[ARG1]] : f32 +! CHECK: %[[SELECT:.*]] = arith.select %[[CMP]], %[[ARG0]], %[[ARG1]] : f32 +! CHECK: acc.yield %[[SELECT]] : f32 +! CHECK: } + +! CHECK-LABEL: acc.reduction.recipe @reduction_min_i32 : i32 reduction_operator init { +! CHECK: ^bb0(%arg0: i32): +! CHECK: %[[INIT:.*]] = arith.constant 2147483647 : i32 +! CHECK: acc.yield %[[INIT]] : i32 +! CHECK: } combiner { +! CHECK: ^bb0(%[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32): +! CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[ARG0]], %[[ARG1]] : i32 +! CHECK: %[[SELECT:.*]] = arith.select %[[CMP]], %[[ARG0]], %[[ARG1]] : i32 +! CHECK: acc.yield %[[SELECT]] : i32 +! CHECK: } + ! CHECK-LABEL: acc.reduction.recipe @reduction_mul_f32 : f32 reduction_operator init { ! CHECK: ^bb0(%{{.*}}: f32): ! CHECK: %[[INIT:.*]] = arith.constant 1.000000e+00 : f32 @@ -97,3 +119,32 @@ ! CHECK-LABEL: func.func @_QPacc_reduction_mul_float( ! CHECK-SAME: %{{.*}}: !fir.ref> {fir.bindc_name = "a"}, %[[B:.*]]: !fir.ref {fir.bindc_name = "b"}) ! CHECK: acc.loop reduction(@reduction_mul_f32 -> %[[B]] : !fir.ref) + + +subroutine acc_reduction_min_int(a, b) + integer :: a(100) + integer :: i, b + + !$acc loop reduction(min:b) + do i = 1, 100 + b = min(b, a(i)) + end do +end subroutine + +! CHECK-LABEL: func.func @_QPacc_reduction_min_int( +! CHECK-SAME: %{{.*}}: !fir.ref> {fir.bindc_name = "a"}, %[[B:.*]]: !fir.ref {fir.bindc_name = "b"}) +! CHECK: acc.loop reduction(@reduction_min_i32 -> %[[B]] : !fir.ref) + +subroutine acc_reduction_min_float(a, b) + real :: a(100), b + integer :: i + + !$acc loop reduction(min:b) + do i = 1, 100 + b = min(b, a(i)) + end do +end subroutine + +! CHECK-LABEL: func.func @_QPacc_reduction_min_float( +! CHECK-SAME: %{{.*}}: !fir.ref> {fir.bindc_name = "a"}, %[[B:.*]]: !fir.ref {fir.bindc_name = "b"}) +! CHECK: acc.loop reduction(@reduction_min_f32 -> %[[B]] : !fir.ref)