[flang-commits] [flang] [flang][OpenACC] Fix reduction init value for minnumf/minimumf/maxnumf/maximumf (PR #187647)
via flang-commits
flang-commits at lists.llvm.org
Fri Mar 20 09:25:32 PDT 2026
https://github.com/khaki3 updated https://github.com/llvm/llvm-project/pull/187647
>From 9a0cb90fa1d889cfff684123d5a17f566cfb73ec Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Fri, 20 Mar 2026 00:17:00 -0700
Subject: [PATCH 1/2] [flang][OpenACC] Fix reduction init value for
minnumf/minimumf/maxnumf/maximumf
The reduction recipe init region was producing 0.0 instead of the
correct identity value (largest representable float for min, smallest
for max) when the reduction operator was AccMinnumf, AccMinimumf,
AccMaxnumf, or AccMaximumf. Only AccMin and AccMax were handled,
causing the new operator variants to fall through to the default
branch which returns 0.
This caused GPU min reductions to always produce 0.0 since
min(x, 0.0) = 0.0 for all positive x.
Made-with: Cursor
---
.../Optimizer/OpenACC/Support/FIROpenACCUtils.cpp | 14 +++++++++++---
flang/test/Lower/OpenACC/acc-reduction-maxmin.f90 | 2 ++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index a53ea9216f7ab..dfe2641f3f80e 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -274,7 +274,9 @@ std::string fir::acc::getRecipeName(mlir::acc::RecipeKind kind, Type type,
/// Get the initial value for reduction operator.
template <typename R>
static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
- if (op == mlir::acc::ReductionOperator::AccMin) {
+ if (op == mlir::acc::ReductionOperator::AccMin ||
+ op == mlir::acc::ReductionOperator::AccMinnumf ||
+ op == mlir::acc::ReductionOperator::AccMinimumf) {
// min init value -> largest
if constexpr (std::is_same_v<R, llvm::APInt>) {
assert(ty.isIntOrIndex() && "expect integer or index type");
@@ -286,7 +288,9 @@ static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
return llvm::APFloat::getLargest(floatTy.getFloatSemantics(),
/*negative=*/false);
}
- } else if (op == mlir::acc::ReductionOperator::AccMax) {
+ } else if (op == mlir::acc::ReductionOperator::AccMax ||
+ op == mlir::acc::ReductionOperator::AccMaxnumf ||
+ op == mlir::acc::ReductionOperator::AccMaximumf) {
// max init value -> smallest
if constexpr (std::is_same_v<R, llvm::APInt>) {
assert(ty.isIntOrIndex() && "expect integer or index type");
@@ -348,7 +352,11 @@ static mlir::Value getReductionInitValue(fir::FirOpBuilder &builder,
builder, loc, ty,
builder.getIntegerAttr(ty, getReductionInitValue<llvm::APInt>(op, ty)));
if (op == mlir::acc::ReductionOperator::AccMin ||
- op == mlir::acc::ReductionOperator::AccMax) {
+ op == mlir::acc::ReductionOperator::AccMinnumf ||
+ op == mlir::acc::ReductionOperator::AccMinimumf ||
+ op == mlir::acc::ReductionOperator::AccMax ||
+ op == mlir::acc::ReductionOperator::AccMaxnumf ||
+ op == mlir::acc::ReductionOperator::AccMaximumf) {
if (mlir::isa<mlir::ComplexType>(ty))
llvm::report_fatal_error(
"min/max reduction not supported for complex type");
diff --git a/flang/test/Lower/OpenACC/acc-reduction-maxmin.f90 b/flang/test/Lower/OpenACC/acc-reduction-maxmin.f90
index 2d0746decf29d..cd6e3fd2fb07b 100644
--- a/flang/test/Lower/OpenACC/acc-reduction-maxmin.f90
+++ b/flang/test/Lower/OpenACC/acc-reduction-maxmin.f90
@@ -61,6 +61,7 @@ end subroutine acc_array_reduction_min
! EXTREMUM: %[[MINIMUMF_0:.*]] = arith.minimumf %{{.*}}, %{{.*}} fastmath<contract> : f32
! EXTREMUM-LABEL: acc.reduction.recipe @reduction_minimumf_ref_f32 : !fir.ref<f32> reduction_operator <minimumf> init {
+! EXTREMUM: %[[CST:.*]] = arith.constant 3.40282347E+38 : f32
! EXTREMUM: } combiner {
! EXTREMUM: %[[MINIMUMF_0:.*]] = arith.minimumf %{{.*}}, %{{.*}} fastmath<contract> : f32
@@ -79,6 +80,7 @@ end subroutine acc_array_reduction_min
! EXTREMENUM: %[[MINNUMF_0:.*]] = arith.minnumf %{{.*}}, %{{.*}} fastmath<contract> : f32
! EXTREMENUM-LABEL: acc.reduction.recipe @reduction_minnumf_ref_f32 : !fir.ref<f32> reduction_operator <minnumf> init {
+! EXTREMENUM: %[[CST:.*]] = arith.constant 3.40282347E+38 : f32
! EXTREMENUM: } combiner {
! EXTREMENUM: %[[MINNUMF_0:.*]] = arith.minnumf %{{.*}}, %{{.*}} fastmath<contract> : f32
>From a91064b9bc4976ee00ca77676183470383c5f202 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Fri, 20 Mar 2026 09:25:22 -0700
Subject: [PATCH 2/2] [flang][OpenACC] Fix reduction init value for
minnumf/minimumf/maxnumf/maximumf
The reduction recipe init region was producing 0.0 instead of the
correct identity value (largest representable float for min, smallest
for max) when the reduction operator was AccMinnumf, AccMinimumf,
AccMaxnumf, or AccMaximumf. Only AccMin and AccMax were handled,
causing the new operator variants to fall through to the default
branch which returns 0.
This caused GPU min reductions to always produce 0.0 since
min(x, 0.0) = 0.0 for all positive x.
Refactor the if/else chain to a switch statement so the compiler
can warn about unhandled enum values when new operators are added.
Made-with: Cursor
---
.../OpenACC/Support/FIROpenACCUtils.cpp | 33 +++++++++++--------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
index dfe2641f3f80e..f600fba0864f2 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCUtils.cpp
@@ -274,9 +274,10 @@ std::string fir::acc::getRecipeName(mlir::acc::RecipeKind kind, Type type,
/// Get the initial value for reduction operator.
template <typename R>
static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
- if (op == mlir::acc::ReductionOperator::AccMin ||
- op == mlir::acc::ReductionOperator::AccMinnumf ||
- op == mlir::acc::ReductionOperator::AccMinimumf) {
+ switch (op) {
+ case mlir::acc::ReductionOperator::AccMin:
+ case mlir::acc::ReductionOperator::AccMinnumf:
+ case mlir::acc::ReductionOperator::AccMinimumf:
// min init value -> largest
if constexpr (std::is_same_v<R, llvm::APInt>) {
assert(ty.isIntOrIndex() && "expect integer or index type");
@@ -288,9 +289,10 @@ static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
return llvm::APFloat::getLargest(floatTy.getFloatSemantics(),
/*negative=*/false);
}
- } else if (op == mlir::acc::ReductionOperator::AccMax ||
- op == mlir::acc::ReductionOperator::AccMaxnumf ||
- op == mlir::acc::ReductionOperator::AccMaximumf) {
+ break;
+ case mlir::acc::ReductionOperator::AccMax:
+ case mlir::acc::ReductionOperator::AccMaxnumf:
+ case mlir::acc::ReductionOperator::AccMaximumf:
// max init value -> smallest
if constexpr (std::is_same_v<R, llvm::APInt>) {
assert(ty.isIntOrIndex() && "expect integer or index type");
@@ -302,30 +304,35 @@ static R getReductionInitValue(mlir::acc::ReductionOperator op, mlir::Type ty) {
return llvm::APFloat::getSmallest(floatTy.getFloatSemantics(),
/*negative=*/true);
}
- } else if (op == mlir::acc::ReductionOperator::AccIand) {
+ break;
+ case mlir::acc::ReductionOperator::AccIand:
if constexpr (std::is_same_v<R, llvm::APInt>) {
assert(ty.isIntOrIndex() && "expect integer type");
unsigned bits = ty.getIntOrFloatBitWidth();
return llvm::APInt::getAllOnes(bits);
}
- } else {
- assert(op != mlir::acc::ReductionOperator::AccNone);
- // +, ior, ieor init value -> 0
- // * init value -> 1
+ break;
+ case mlir::acc::ReductionOperator::AccAdd:
+ case mlir::acc::ReductionOperator::AccMul:
+ case mlir::acc::ReductionOperator::AccIor:
+ case mlir::acc::ReductionOperator::AccXor: {
+ // +, ior, ieor init value -> 0; * init value -> 1
int64_t value = (op == mlir::acc::ReductionOperator::AccMul) ? 1 : 0;
if constexpr (std::is_same_v<R, llvm::APInt>) {
assert(ty.isIntOrIndex() && "expect integer or index type");
return llvm::APInt(ty.getIntOrFloatBitWidth(), value, true);
}
-
if constexpr (std::is_same_v<R, llvm::APFloat>) {
assert(mlir::isa<mlir::FloatType>(ty) && "expect float type");
auto floatTy = mlir::dyn_cast<mlir::FloatType>(ty);
return llvm::APFloat(floatTy.getFloatSemantics(), value);
}
-
if constexpr (std::is_same_v<R, int64_t>)
return value;
+ break;
+ }
+ default:
+ llvm_unreachable("OpenACC reduction unsupported operator");
}
llvm_unreachable("OpenACC reduction unsupported type");
}
More information about the flang-commits
mailing list