[flang-commits] [flang] [flang] Use integer arith.max/min operations for max/min lowering. (PR #186466)

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Tue Mar 17 08:12:16 PDT 2026


https://github.com/vzakhari updated https://github.com/llvm/llvm-project/pull/186466

>From 6740c3461f9ceb4d5f9308e83f61797fdbfe6101 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Fri, 13 Mar 2026 10:21:08 -0700
Subject: [PATCH 1/5] [flang] Use integer arith.max/min operations for max/min
 lowering.

arith.maxsi/maxui/minsi/minui are more concise than cmp+select
and probably allow more folding, so we should use it in Flang lowering.
---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 35 ++++++-----
 .../Lower/HLFIR/array-ctor-as-elemental.f90   |  3 +-
 .../HLFIR/array-ctor-as-inlined-temp.f90      | 12 ++--
 flang/test/Lower/HLFIR/binary-ops.f90         |  3 +-
 flang/test/Lower/HLFIR/custom-intrinsic.f90   | 60 +++++++------------
 flang/test/Lower/Intrinsics/max.f90           | 30 ++++------
 .../Lower/OpenACC/acc-atomic-update-hlfir.f90 |  9 +--
 flang/test/Lower/OpenACC/acc-reduction.f90    | 12 ++--
 flang/test/Lower/OpenMP/atomic-update.f90     |  6 +-
 .../OpenMP/minmax-optional-parameters.f90     |  9 +--
 .../omp-declare-reduction-derivedtype.f90     |  3 +-
 .../OpenMP/reduction-array-intrinsic.f90      |  3 +-
 ...oop-reduction-allocatable-array-minmax.f90 |  6 +-
 .../OpenMP/wsloop-reduction-max-2-byref.f90   |  3 +-
 .../Lower/OpenMP/wsloop-reduction-max-2.f90   |  3 +-
 .../OpenMP/wsloop-reduction-max-byref.f90     |  3 +-
 .../Lower/OpenMP/wsloop-reduction-max.f90     |  3 +-
 .../OpenMP/wsloop-reduction-min-byref.f90     |  3 +-
 .../Lower/OpenMP/wsloop-reduction-min.f90     |  3 +-
 .../Lower/OpenMP/wsloop-reduction-multi.f90   |  2 +-
 flang/test/Lower/array-elemental-calls-2.f90  |  3 +-
 21 files changed, 77 insertions(+), 137 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index d67eebdd8c93c..f421bddebea8a 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -8736,12 +8736,6 @@ static mlir::Value genExtremumResult(mlir::Location loc,
                                      fir::FirOpBuilder &builder,
                                      mlir::Value left, mlir::Value right) {
   mlir::Type type = left.getType();
-  mlir::arith::CmpIPredicate integerPredicate =
-      type.isUnsignedInteger() ? isMax ? mlir::arith::CmpIPredicate::ugt
-                                       : mlir::arith::CmpIPredicate::ult
-      : isMax                  ? mlir::arith::CmpIPredicate::sgt
-                               : mlir::arith::CmpIPredicate::slt;
-  mlir::Value pred;
   if (fir::isa_real(type)) {
     switch (builder.getFPMaxminBehavior()) {
     case Fortran::common::FPMaxminBehavior::Portable:
@@ -8782,26 +8776,31 @@ static mlir::Value genExtremumResult(mlir::Location loc,
 
     llvm_unreachable("unsupported FPMaxminBehavior");
   } else if (fir::isa_integer(type)) {
-    mlir::Value cmpLeft = left;
-    mlir::Value cmpRight = right;
+    // It is probably okay to use signed index.maxs/mins, but
+    // maybe the caller needs to specify signedness.
+    // There are currently no callers that pass values of index
+    // type, so just emit a TODO.
+    if (mlir::isa<mlir::IndexType>(type))
+      TODO(loc, "extremum for index type");
+
     if (type.isUnsignedInteger()) {
-      mlir::Type signlessType = mlir::IntegerType::get(
-          builder.getContext(), type.getIntOrFloatBitWidth(),
-          mlir::IntegerType::SignednessSemantics::Signless);
-      cmpLeft = builder.createConvert(loc, signlessType, left);
-      cmpRight = builder.createConvert(loc, signlessType, right);
+      if constexpr (isMax)
+        return mlir::arith::MaxUIOp::create(builder, loc, left, right);
+      else
+        return mlir::arith::MinUIOp::create(builder, loc, left, right);
+    } else {
+      if constexpr (isMax)
+        return mlir::arith::MaxSIOp::create(builder, loc, left, right);
+      else
+        return mlir::arith::MinSIOp::create(builder, loc, left, right);
     }
-    pred = mlir::arith::CmpIOp::create(builder, loc, integerPredicate, cmpLeft,
-                                       cmpRight);
   } else if (fir::isa_char(type) || fir::isa_char(fir::unwrapRefType(type))) {
     // TODO: ! character min and max is tricky because the result
     // length is the length of the longest argument!
     // So we may need a temp.
     TODO(loc, "intrinsic: min and max for CHARACTER");
   }
-  assert(pred && "pred must be defined");
-
-  return mlir::arith::SelectOp::create(builder, loc, pred, left, right);
+  llvm_unreachable("unsupported extremum");
 }
 
 // UNLINK
diff --git a/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90 b/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90
index 5c4f079c86e20..f52216d2f558d 100644
--- a/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-as-elemental.f90
@@ -54,8 +54,7 @@ subroutine test_as_strided_elemental(lb, ub, stride)
 ! CHECK:           %[[VAL_12:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i64>
 ! CHECK:           %[[VAL_13:.*]] = arith.divsi %[[VAL_11]], %[[VAL_12]] : i64
 ! CHECK:           %[[VAL_14:.*]] = arith.constant 0 : i64
-! CHECK:           %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_14]] : i64
-! CHECK:           %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i64
+! CHECK:           %[[VAL_16:.*]] = arith.maxsi %[[VAL_13]], %[[VAL_14]] : i64
 ! CHECK:           %[[VAL_17:.*]] = arith.addi %[[VAL_6]], %[[VAL_16]] : i64
 ! CHECK:           %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i64) -> index
 ! CHECK:           %[[VAL_19:.*]] = fir.shape %[[VAL_18]] : (index) -> !fir.shape<1>
diff --git a/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90
index 415a9df5bf838..6fcd942f4a1e5 100644
--- a/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90
@@ -127,8 +127,7 @@ subroutine test_implied_do(n)
 ! CHECK:           %[[VAL_10:.*]] = arith.constant 1 : i64
 ! CHECK:           %[[VAL_11:.*]] = arith.divsi %[[VAL_9]], %[[VAL_10]] : i64
 ! CHECK:           %[[VAL_12:.*]] = arith.constant 0 : i64
-! CHECK:           %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : i64
-! CHECK:           %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : i64
+! CHECK:           %[[VAL_14:.*]] = arith.maxsi %[[VAL_11]], %[[VAL_12]] : i64
 ! CHECK:           %[[VAL_15:.*]] = arith.muli %[[VAL_4]], %[[VAL_14]] : i64
 ! CHECK:           %[[VAL_16:.*]] = arith.addi %[[VAL_3]], %[[VAL_15]] : i64
 ! CHECK:           %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i64) -> index
@@ -191,8 +190,7 @@ subroutine test_strided_implied_do(lb, ub, stride)
 ! CHECK:           %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i64>
 ! CHECK:           %[[VAL_15:.*]] = arith.divsi %[[VAL_13]], %[[VAL_14]] : i64
 ! CHECK:           %[[VAL_16:.*]] = arith.constant 0 : i64
-! CHECK:           %[[VAL_17:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_16]] : i64
-! CHECK:           %[[VAL_18:.*]] = arith.select %[[VAL_17]], %[[VAL_15]], %[[VAL_16]] : i64
+! CHECK:           %[[VAL_18:.*]] = arith.maxsi %[[VAL_15]], %[[VAL_16]] : i64
 ! CHECK:           %[[VAL_19:.*]] = arith.muli %[[VAL_8]], %[[VAL_18]] : i64
 ! CHECK:           %[[VAL_20:.*]] = arith.addi %[[VAL_7]], %[[VAL_19]] : i64
 ! CHECK:           %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index
@@ -253,8 +251,7 @@ subroutine test_nested_implied_do(n, m)
 ! CHECK:           %[[VAL_12:.*]] = arith.constant 1 : i64
 ! CHECK:           %[[VAL_13:.*]] = arith.divsi %[[VAL_11]], %[[VAL_12]] : i64
 ! CHECK:           %[[VAL_14:.*]] = arith.constant 0 : i64
-! CHECK:           %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_14]] : i64
-! CHECK:           %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i64
+! CHECK:           %[[VAL_16:.*]] = arith.maxsi %[[VAL_13]], %[[VAL_14]] : i64
 ! CHECK:           %[[VAL_17:.*]] = arith.addi %[[VAL_6]], %[[VAL_16]] : i64
 ! CHECK:           %[[VAL_18:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i64>
 ! CHECK:           %[[VAL_19:.*]] = arith.constant 1 : i64
@@ -264,8 +261,7 @@ subroutine test_nested_implied_do(n, m)
 ! CHECK:           %[[VAL_23:.*]] = arith.constant 1 : i64
 ! CHECK:           %[[VAL_24:.*]] = arith.divsi %[[VAL_22]], %[[VAL_23]] : i64
 ! CHECK:           %[[VAL_25:.*]] = arith.constant 0 : i64
-! CHECK:           %[[VAL_26:.*]] = arith.cmpi sgt, %[[VAL_24]], %[[VAL_25]] : i64
-! CHECK:           %[[VAL_27:.*]] = arith.select %[[VAL_26]], %[[VAL_24]], %[[VAL_25]] : i64
+! CHECK:           %[[VAL_27:.*]] = arith.maxsi %[[VAL_24]], %[[VAL_25]] : i64
 ! CHECK:           %[[VAL_28:.*]] = arith.muli %[[VAL_17]], %[[VAL_27]] : i64
 ! CHECK:           %[[VAL_29:.*]] = arith.addi %[[VAL_5]], %[[VAL_28]] : i64
 ! CHECK:           %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i64) -> index
diff --git a/flang/test/Lower/HLFIR/binary-ops.f90 b/flang/test/Lower/HLFIR/binary-ops.f90
index f4e1643dd78b6..3a83cd44d3c2e 100644
--- a/flang/test/Lower/HLFIR/binary-ops.f90
+++ b/flang/test/Lower/HLFIR/binary-ops.f90
@@ -206,8 +206,7 @@ subroutine extremum(c, n, l)
 ! CHECK:  hlfir.declare {{.*}}c"}
 ! CHECK:  %[[VAL_11:.*]] = arith.constant 0 : i64
 ! CHECK:  %[[VAL_12:.*]] = fir.load %{{.*}} : !fir.ref<i64>
-! CHECK:  %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : i64
-! CHECK:  arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : i64
+! CHECK:  arith.maxsi %[[VAL_11]], %[[VAL_12]] : i64
 
 subroutine cmp_int(l, x, y)
   logical :: l
diff --git a/flang/test/Lower/HLFIR/custom-intrinsic.f90 b/flang/test/Lower/HLFIR/custom-intrinsic.f90
index 4999eebf376e7..294077105ed7b 100644
--- a/flang/test/Lower/HLFIR/custom-intrinsic.f90
+++ b/flang/test/Lower/HLFIR/custom-intrinsic.f90
@@ -14,8 +14,7 @@ function max_simple(a, b)
 ! CHECK-NEXT:    %[[RES_DECL:.*]]:2 = hlfir.declare %[[RES_ALLOC]] {uniq_name = "_QFmax_simpleEmax_simple"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 ! CHECK-NEXT:    %[[A_LD:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref<i32>
 ! CHECK-NEXT:    %[[B_LD:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref<i32>
-! CHECK-NEXT:    %[[A_GT_B:.*]] = arith.cmpi sgt, %[[A_LD]], %[[B_LD]] : i32
-! CHECK-NEXT:    %[[SELECT:.*]] = arith.select %[[A_GT_B]], %[[A_LD]], %[[B_LD]] : i32
+! CHECK-NEXT:    %[[SELECT:.*]] = arith.maxsi %[[A_LD]], %[[B_LD]] : i32
 ! CHECK-NEXT:    hlfir.assign %[[SELECT]] to %[[RES_DECL]]#0 : i32, !fir.ref<i32>
 ! CHECK-NEXT:    %[[RES_LD:.*]] = fir.load %[[RES_DECL]]#0 : !fir.ref<i32>
 ! CHECK-NEXT:    return %[[RES_LD]] : i32
@@ -38,12 +37,10 @@ function max_dynamic_optional_scalar(a, b, c)
 ! CHECK:           %[[VAL_8:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_9:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_10:.*]] = fir.is_present %[[VAL_5]]#0 : (!fir.ref<i32>) -> i1
-! CHECK:           %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_9]] : i32
-! CHECK:           %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_8]], %[[VAL_9]] : i32
+! CHECK:           %[[VAL_12:.*]] = arith.maxsi %[[VAL_8]], %[[VAL_9]] : i32
 ! CHECK:           %[[VAL_13:.*]] = fir.if %[[VAL_10]] -> (i32) {
 ! CHECK:             %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
-! CHECK:             %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_14]] : i32
-! CHECK:             %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_12]], %[[VAL_14]] : i32
+! CHECK:             %[[VAL_16:.*]] = arith.maxsi %[[VAL_12]], %[[VAL_14]] : i32
 ! CHECK:             fir.result %[[VAL_16]] : i32
 ! CHECK:           } else {
 ! CHECK:             fir.result %[[VAL_12]] : i32
@@ -73,20 +70,17 @@ function max_dynamic_optional_scalar2(a, b, c, d)
 ! CHECK:           %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_12:.*]] = fir.is_present %[[VAL_6]]#0 : (!fir.ref<i32>) -> i1
 ! CHECK:           %[[VAL_13:.*]] = fir.is_present %[[VAL_7]]#0 : (!fir.ref<i32>) -> i1
-! CHECK:           %[[VAL_14:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_11]] : i32
-! CHECK:           %[[VAL_15:.*]] = arith.select %[[VAL_14]], %[[VAL_10]], %[[VAL_11]] : i32
+! CHECK:           %[[VAL_15:.*]] = arith.maxsi %[[VAL_10]], %[[VAL_11]] : i32
 ! CHECK:           %[[VAL_16:.*]] = fir.if %[[VAL_12]] -> (i32) {
 ! CHECK:             %[[VAL_17:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref<i32>
-! CHECK:             %[[VAL_18:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_17]] : i32
-! CHECK:             %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_15]], %[[VAL_17]] : i32
+! CHECK:             %[[VAL_19:.*]] = arith.maxsi %[[VAL_15]], %[[VAL_17]] : i32
 ! CHECK:             fir.result %[[VAL_19]] : i32
 ! CHECK:           } else {
 ! CHECK:             fir.result %[[VAL_15]] : i32
 ! CHECK:           }
 ! CHECK:           %[[VAL_20:.*]] = fir.if %[[VAL_13]] -> (i32) {
 ! CHECK:             %[[VAL_21:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<i32>
-! CHECK:             %[[VAL_22:.*]] = arith.cmpi sgt, %[[VAL_23:.*]], %[[VAL_21]] : i32
-! CHECK:             %[[VAL_24:.*]] = arith.select %[[VAL_22]], %[[VAL_23]], %[[VAL_21]] : i32
+! CHECK:             %[[VAL_24:.*]] = arith.maxsi %[[VAL_23:.*]], %[[VAL_21]] : i32
 ! CHECK:             fir.result %[[VAL_24]] : i32
 ! CHECK:           } else {
 ! CHECK:             fir.result %[[VAL_25:.*]] : i32
@@ -119,8 +113,7 @@ function max_array(a, b)
 ! CHECK-DAG:             %[[VAL_15:.*]] = fir.load %[[VAL_14]] : !fir.ref<i32>
 ! CHECK-DAG:             %[[VAL_16:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_13]])  : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
 ! CHECK-DAG:             %[[VAL_17:.*]] = fir.load %[[VAL_16]] : !fir.ref<i32>
-! CHECK:             %[[VAL_18:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_17]] : i32
-! CHECK:             %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_15]], %[[VAL_17]] : i32
+! CHECK:             %[[VAL_19:.*]] = arith.maxsi %[[VAL_15]], %[[VAL_17]] : i32
 ! CHECK:             hlfir.yield_element %[[VAL_19]] : i32
 ! CHECK:           }
 ! CHECK:           hlfir.assign %[[VAL_20:.*]] to %[[VAL_11]]#0 : !hlfir.expr<42xi32>, !fir.ref<!fir.array<42xi32>>
@@ -155,13 +148,11 @@ function max_dynamic_optional_array(a, b, c)
 ! CHECK:           ^bb0(%[[VAL_17:.*]]: index):
 ! CHECK:             %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_17]])  : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             %[[VAL_19:.*]] = fir.load %[[VAL_18]] : !fir.ref<i32>
-! CHECK:             %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_19]] : i32
-! CHECK:             %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_15]], %[[VAL_19]] : i32
+! CHECK:             %[[VAL_21:.*]] = arith.maxsi %[[VAL_15]], %[[VAL_19]] : i32
 ! CHECK:             %[[VAL_22:.*]] = fir.if %[[VAL_14]] -> (i32) {
 ! CHECK:               %[[VAL_23:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_17]])  : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
 ! CHECK:               %[[VAL_24:.*]] = fir.load %[[VAL_23]] : !fir.ref<i32>
-! CHECK:               %[[VAL_25:.*]] = arith.cmpi sgt, %[[VAL_21]], %[[VAL_24]] : i32
-! CHECK:               %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_21]], %[[VAL_24]] : i32
+! CHECK:               %[[VAL_26:.*]] = arith.maxsi %[[VAL_21]], %[[VAL_24]] : i32
 ! CHECK:               fir.result %[[VAL_26]] : i32
 ! CHECK:             } else {
 ! CHECK:               fir.result %[[VAL_21]] : i32
@@ -187,8 +178,7 @@ function min_simple(a, b)
 ! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFmin_simpleEmin_simple"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 ! CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_7:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
-! CHECK:           %[[VAL_8:.*]] = arith.cmpi slt, %[[VAL_6]], %[[VAL_7]] : i32
-! CHECK:           %[[VAL_9:.*]] = arith.select %[[VAL_8]], %[[VAL_6]], %[[VAL_7]] : i32
+! CHECK:           %[[VAL_9:.*]] = arith.minsi %[[VAL_6]], %[[VAL_7]] : i32
 ! CHECK:           hlfir.assign %[[VAL_9]] to %[[VAL_5]]#0 : i32, !fir.ref<i32>
 ! CHECK:           %[[VAL_10:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
 ! CHECK:           return %[[VAL_10]] : i32
@@ -211,12 +201,10 @@ function min_dynamic_optional_scalar(a, b, c)
 ! CHECK:           %[[VAL_8:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_9:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_10:.*]] = fir.is_present %[[VAL_5]]#0 : (!fir.ref<i32>) -> i1
-! CHECK:           %[[VAL_11:.*]] = arith.cmpi slt, %[[VAL_8]], %[[VAL_9]] : i32
-! CHECK:           %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_8]], %[[VAL_9]] : i32
+! CHECK:           %[[VAL_12:.*]] = arith.minsi %[[VAL_8]], %[[VAL_9]] : i32
 ! CHECK:           %[[VAL_13:.*]] = fir.if %[[VAL_10]] -> (i32) {
 ! CHECK:             %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
-! CHECK:             %[[VAL_15:.*]] = arith.cmpi slt, %[[VAL_12]], %[[VAL_14]] : i32
-! CHECK:             %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_12]], %[[VAL_14]] : i32
+! CHECK:             %[[VAL_16:.*]] = arith.minsi %[[VAL_12]], %[[VAL_14]] : i32
 ! CHECK:             fir.result %[[VAL_16]] : i32
 ! CHECK:           } else {
 ! CHECK:             fir.result %[[VAL_12]] : i32
@@ -246,20 +234,17 @@ function min_dynamic_optional_scalar2(a, b, c, d)
 ! CHECK:           %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
 ! CHECK:           %[[VAL_12:.*]] = fir.is_present %[[VAL_6]]#0 : (!fir.ref<i32>) -> i1
 ! CHECK:           %[[VAL_13:.*]] = fir.is_present %[[VAL_7]]#0 : (!fir.ref<i32>) -> i1
-! CHECK:           %[[VAL_14:.*]] = arith.cmpi slt, %[[VAL_10]], %[[VAL_11]] : i32
-! CHECK:           %[[VAL_15:.*]] = arith.select %[[VAL_14]], %[[VAL_10]], %[[VAL_11]] : i32
+! CHECK:           %[[VAL_15:.*]] = arith.minsi %[[VAL_10]], %[[VAL_11]] : i32
 ! CHECK:           %[[VAL_16:.*]] = fir.if %[[VAL_12]] -> (i32) {
 ! CHECK:             %[[VAL_17:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref<i32>
-! CHECK:             %[[VAL_18:.*]] = arith.cmpi slt, %[[VAL_15]], %[[VAL_17]] : i32
-! CHECK:             %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_15]], %[[VAL_17]] : i32
+! CHECK:             %[[VAL_19:.*]] = arith.minsi %[[VAL_15]], %[[VAL_17]] : i32
 ! CHECK:             fir.result %[[VAL_19]] : i32
 ! CHECK:           } else {
 ! CHECK:             fir.result %[[VAL_15]] : i32
 ! CHECK:           }
 ! CHECK:           %[[VAL_20:.*]] = fir.if %[[VAL_13]] -> (i32) {
 ! CHECK:             %[[VAL_21:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<i32>
-! CHECK:             %[[VAL_22:.*]] = arith.cmpi slt, %[[VAL_23:.*]], %[[VAL_21]] : i32
-! CHECK:             %[[VAL_24:.*]] = arith.select %[[VAL_22]], %[[VAL_23]], %[[VAL_21]] : i32
+! CHECK:             %[[VAL_24:.*]] = arith.minsi %[[VAL_23:.*]], %[[VAL_21]] : i32
 ! CHECK:             fir.result %[[VAL_24]] : i32
 ! CHECK:           } else {
 ! CHECK:             fir.result %[[VAL_25:.*]] : i32
@@ -292,8 +277,7 @@ function min_array(a, b)
 ! CHECK-DAG:             %[[VAL_15:.*]] = fir.load %[[VAL_14]] : !fir.ref<i32>
 ! CHECK-DAG:             %[[VAL_16:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_13]])  : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
 ! CHECK-DAG:             %[[VAL_17:.*]] = fir.load %[[VAL_16]] : !fir.ref<i32>
-! CHECK:             %[[VAL_18:.*]] = arith.cmpi slt, %[[VAL_15]], %[[VAL_17]] : i32
-! CHECK:             %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_15]], %[[VAL_17]] : i32
+! CHECK:             %[[VAL_19:.*]] = arith.minsi %[[VAL_15]], %[[VAL_17]] : i32
 ! CHECK:             hlfir.yield_element %[[VAL_19]] : i32
 ! CHECK:           }
 ! CHECK:           hlfir.assign %[[VAL_20:.*]] to %[[VAL_11]]#0 : !hlfir.expr<42xi32>, !fir.ref<!fir.array<42xi32>>
@@ -328,13 +312,11 @@ function min_dynamic_optional_array(a, b, c)
 ! CHECK:           ^bb0(%[[VAL_17:.*]]: index):
 ! CHECK:             %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_17]])  : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             %[[VAL_19:.*]] = fir.load %[[VAL_18]] : !fir.ref<i32>
-! CHECK:             %[[VAL_20:.*]] = arith.cmpi slt, %[[VAL_15]], %[[VAL_19]] : i32
-! CHECK:             %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_15]], %[[VAL_19]] : i32
+! CHECK:             %[[VAL_21:.*]] = arith.minsi %[[VAL_15]], %[[VAL_19]] : i32
 ! CHECK:             %[[VAL_22:.*]] = fir.if %[[VAL_14]] -> (i32) {
 ! CHECK:               %[[VAL_23:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_17]])  : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
 ! CHECK:               %[[VAL_24:.*]] = fir.load %[[VAL_23]] : !fir.ref<i32>
-! CHECK:               %[[VAL_25:.*]] = arith.cmpi slt, %[[VAL_21]], %[[VAL_24]] : i32
-! CHECK:               %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_21]], %[[VAL_24]] : i32
+! CHECK:               %[[VAL_26:.*]] = arith.minsi %[[VAL_21]], %[[VAL_24]] : i32
 ! CHECK:               fir.result %[[VAL_26]] : i32
 ! CHECK:             } else {
 ! CHECK:               fir.result %[[VAL_21]] : i32
@@ -812,8 +794,7 @@ subroutine allocatables_test(a, b, c)
 ! CHECK:             %[[VAL_112:.*]] = arith.addi %[[VAL_84]], %[[VAL_111]] : index
 ! CHECK:             %[[VAL_113:.*]] = hlfir.designate %[[VAL_79]] (%[[VAL_108]], %[[VAL_110]], %[[VAL_112]])  : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index, index, index) -> !fir.ref<i32>
 ! CHECK:             %[[VAL_114:.*]] = fir.load %[[VAL_113]] : !fir.ref<i32>
-! CHECK:             %[[VAL_115:.*]] = arith.cmpi slt, %[[VAL_99]], %[[VAL_114]] : i32
-! CHECK:             %[[VAL_116:.*]] = arith.select %[[VAL_115]], %[[VAL_99]], %[[VAL_114]] : i32
+! CHECK:             %[[VAL_116:.*]] = arith.minsi %[[VAL_99]], %[[VAL_114]] : i32
 ! CHECK:             %[[VAL_117:.*]] = fir.if %[[VAL_70]] -> (i32) {
 ! CHECK:               %[[VAL_118:.*]] = arith.constant 0 : index
 ! CHECK:               %[[VAL_119:.*]]:3 = fir.box_dims %[[VAL_80]], %[[VAL_118]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
@@ -830,8 +811,7 @@ subroutine allocatables_test(a, b, c)
 ! CHECK:               %[[VAL_130:.*]] = arith.addi %[[VAL_84]], %[[VAL_129]] : index
 ! CHECK:               %[[VAL_131:.*]] = hlfir.designate %[[VAL_80]] (%[[VAL_126]], %[[VAL_128]], %[[VAL_130]])  : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index, index, index) -> !fir.ref<i32>
 ! CHECK:               %[[VAL_132:.*]] = fir.load %[[VAL_131]] : !fir.ref<i32>
-! CHECK:               %[[VAL_133:.*]] = arith.cmpi slt, %[[VAL_116]], %[[VAL_132]] : i32
-! CHECK:               %[[VAL_134:.*]] = arith.select %[[VAL_133]], %[[VAL_116]], %[[VAL_132]] : i32
+! CHECK:               %[[VAL_134:.*]] = arith.minsi %[[VAL_116]], %[[VAL_132]] : i32
 ! CHECK:               fir.result %[[VAL_134]] : i32
 ! CHECK:             } else {
 ! CHECK:               fir.result %[[VAL_116]] : i32
diff --git a/flang/test/Lower/Intrinsics/max.f90 b/flang/test/Lower/Intrinsics/max.f90
index c3d2457ef1af1..9c83d2ec6eadd 100644
--- a/flang/test/Lower/Intrinsics/max.f90
+++ b/flang/test/Lower/Intrinsics/max.f90
@@ -17,12 +17,10 @@ subroutine dynamic_optional(a, b, c)
     ! CHECK:  fir.do_loop %[[VAL_26:.*]] = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%[[VAL_27:.*]] = %{{.*}}) -> (!fir.array<?xi32>) {
     ! CHECK:    %[[VAL_28:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_26]] : (!fir.array<?xi32>, index) -> i32
     ! CHECK:    %[[VAL_29:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_26]] : (!fir.array<?xi32>, index) -> i32
-    ! CHECK:    %[[VAL_30:.*]] = arith.cmpi sgt, %[[VAL_28]], %[[VAL_29]] : i32
-    ! CHECK:    %[[VAL_31:.*]] = arith.select %[[VAL_30]], %[[VAL_28]], %[[VAL_29]] : i32
+    ! CHECK:    %[[VAL_31:.*]] = arith.maxsi %[[VAL_28]], %[[VAL_29]] : i32
     ! CHECK:    %[[VAL_32:.*]] = fir.if %[[VAL_12]] -> (i32) {
     ! CHECK:      %[[VAL_33:.*]] = fir.array_fetch %[[VAL_18]], %[[VAL_26]] : (!fir.array<?xi32>, index) -> i32
-    ! CHECK:      %[[VAL_34:.*]] = arith.cmpi sgt, %[[VAL_31]], %[[VAL_33]] : i32
-    ! CHECK:      %[[VAL_35:.*]] = arith.select %[[VAL_34]], %[[VAL_31]], %[[VAL_33]] : i32
+    ! CHECK:      %[[VAL_35:.*]] = arith.maxsi %[[VAL_31]], %[[VAL_33]] : i32
     ! CHECK:      fir.result %[[VAL_35]] : i32
     ! CHECK:    } else {
     ! CHECK:      fir.result %[[VAL_31]] : i32
@@ -47,12 +45,10 @@ subroutine dynamic_optional_array_expr_scalar_optional(a, b, c)
     ! CHECK:  fir.do_loop %[[VAL_20:.*]] = %{{.*}} to %{{.*}} step %{{.*}} unordered iter_args(%[[VAL_21:.*]] = %{{.*}}) -> (!fir.array<?xi32>) {
     ! CHECK:    %[[VAL_22:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_20]] : (!fir.array<?xi32>, index) -> i32
     ! CHECK:    %[[VAL_23:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_20]] : (!fir.array<?xi32>, index) -> i32
-    ! CHECK:    %[[VAL_24:.*]] = arith.cmpi sgt, %[[VAL_22]], %[[VAL_23]] : i32
-    ! CHECK:    %[[VAL_25:.*]] = arith.select %[[VAL_24]], %[[VAL_22]], %[[VAL_23]] : i32
+    ! CHECK:    %[[VAL_25:.*]] = arith.maxsi %[[VAL_22]], %[[VAL_23]] : i32
     ! CHECK:    %[[VAL_26:.*]] = fir.if %[[VAL_12]] -> (i32) {
     ! CHECK:      %[[VAL_27:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
-    ! CHECK:      %[[VAL_28:.*]] = arith.cmpi sgt, %[[VAL_25]], %[[VAL_27]] : i32
-    ! CHECK:      %[[VAL_29:.*]] = arith.select %[[VAL_28]], %[[VAL_25]], %[[VAL_27]] : i32
+    ! CHECK:      %[[VAL_29:.*]] = arith.maxsi %[[VAL_25]], %[[VAL_27]] : i32
     ! CHECK:      fir.result %[[VAL_29]] : i32
     ! CHECK:    } else {
     ! CHECK:      fir.result %[[VAL_25]] : i32
@@ -73,12 +69,10 @@ subroutine dynamic_optional_scalar(a, b, c)
     ! CHECK:  %[[VAL_8:.*]] = fir.load %[[VAL_0]] : !fir.ref<i32>
     ! CHECK:  %[[VAL_9:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
     ! CHECK:  %[[VAL_10:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref<i32>) -> i1
-    ! CHECK:  %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_9]] : i32
-    ! CHECK:  %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_8]], %[[VAL_9]] : i32
+    ! CHECK:  %[[VAL_12:.*]] = arith.maxsi %[[VAL_8]], %[[VAL_9]] : i32
     ! CHECK:  %[[VAL_13:.*]] = fir.if %[[VAL_10]] -> (i32) {
     ! CHECK:    %[[VAL_14:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
-    ! CHECK:    %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_14]] : i32
-    ! CHECK:    %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_12]], %[[VAL_14]] : i32
+    ! CHECK:    %[[VAL_16:.*]] = arith.maxsi %[[VAL_12]], %[[VAL_14]] : i32
     ! CHECK:    fir.result %[[VAL_16]] : i32
     ! CHECK:  } else {
     ! CHECK:    fir.result %[[VAL_12]] : i32
@@ -102,22 +96,18 @@ subroutine dynamic_optional_weird(a, b, c, d, e)
     ! CHECK:  %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref<i32>) -> i1
     ! CHECK:  %[[VAL_13:.*]] = fir.load %[[VAL_3]] : !fir.ref<i32>
     ! CHECK:  %[[VAL_14:.*]] = fir.is_present %[[VAL_4]] : (!fir.ref<i32>) -> i1
-    ! CHECK:  %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_11]] : i32
-    ! CHECK:  %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_10]], %[[VAL_11]] : i32
+    ! CHECK:  %[[VAL_16:.*]] = arith.maxsi %[[VAL_10]], %[[VAL_11]] : i32
     ! CHECK:  %[[VAL_17:.*]] = fir.if %[[VAL_12]] -> (i32) {
     ! CHECK:    %[[VAL_18:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
-    ! CHECK:    %[[VAL_19:.*]] = arith.cmpi sgt, %[[VAL_16]], %[[VAL_18]] : i32
-    ! CHECK:    %[[VAL_20:.*]] = arith.select %[[VAL_19]], %[[VAL_16]], %[[VAL_18]] : i32
+    ! CHECK:    %[[VAL_20:.*]] = arith.maxsi %[[VAL_16]], %[[VAL_18]] : i32
     ! CHECK:    fir.result %[[VAL_20]] : i32
     ! CHECK:  } else {
     ! CHECK:    fir.result %[[VAL_16]] : i32
     ! CHECK:  }
-    ! CHECK:  %[[VAL_21:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_13]] : i32
-    ! CHECK:  %[[VAL_23:.*]] = arith.select %[[VAL_21]], %[[VAL_17]], %[[VAL_13]] : i32
+    ! CHECK:  %[[VAL_23:.*]] = arith.maxsi %[[VAL_17]], %[[VAL_13]] : i32
     ! CHECK:  %[[VAL_24:.*]] = fir.if %[[VAL_14]] -> (i32) {
     ! CHECK:    %[[VAL_25:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
-    ! CHECK:    %[[VAL_26:.*]] = arith.cmpi sgt, %[[VAL_23]], %[[VAL_25]] : i32
-    ! CHECK:    %[[VAL_27:.*]] = arith.select %[[VAL_26]], %[[VAL_23]], %[[VAL_25]] : i32
+    ! CHECK:    %[[VAL_27:.*]] = arith.maxsi %[[VAL_23]], %[[VAL_25]] : i32
     ! CHECK:    fir.result %[[VAL_27]] : i32
     ! CHECK:  } else {
     ! CHECK:    fir.result %[[VAL_23]] : i32
diff --git a/flang/test/Lower/OpenACC/acc-atomic-update-hlfir.f90 b/flang/test/Lower/OpenACC/acc-atomic-update-hlfir.f90
index de24b8e75f90f..dc21550084d4a 100644
--- a/flang/test/Lower/OpenACC/acc-atomic-update-hlfir.f90
+++ b/flang/test/Lower/OpenACC/acc-atomic-update-hlfir.f90
@@ -37,12 +37,9 @@ subroutine sb
 !CHECK:   %[[Y_VAL:.*]] = fir.load %[[Y_DECL]]#0 : !fir.ref<i32>
 !CHECK:   acc.atomic.update %[[Z_DECL]]#0 : !fir.ref<i32> {
 !CHECK:   ^bb0(%[[ARG_Z:.*]]: i32):
-!CHECK:     %[[WX_CMP:.*]] = arith.cmpi slt, %[[W_VAL]], %[[X_VAL]] : i32
-!CHECK:     %[[WX_MIN:.*]] = arith.select %[[WX_CMP]], %[[W_VAL]], %[[X_VAL]] : i32
-!CHECK:     %[[WXY_CMP:.*]] = arith.cmpi slt, %[[WX_MIN]], %[[Y_VAL]] : i32
-!CHECK:     %[[WXY_MIN:.*]] = arith.select %[[WXY_CMP]], %[[WX_MIN]], %[[Y_VAL]] : i32
-!CHECK:     %[[WXYZ_CMP:.*]] = arith.cmpi slt, %[[WXY_MIN]], %[[ARG_Z]] : i32
-!CHECK:     %[[WXYZ_MIN:.*]] = arith.select %[[WXYZ_CMP]], %[[WXY_MIN]], %[[ARG_Z]] : i32
+!CHECK:     %[[WX_MIN:.*]] = arith.minsi %[[W_VAL]], %[[X_VAL]] : i32
+!CHECK:     %[[WXY_MIN:.*]] = arith.minsi %[[WX_MIN]], %[[Y_VAL]] : i32
+!CHECK:     %[[WXYZ_MIN:.*]] = arith.minsi %[[WXY_MIN]], %[[ARG_Z]] : i32
 !CHECK:     acc.yield %[[WXYZ_MIN]] : i32
 !CHECK:   }
   !$acc atomic update
diff --git a/flang/test/Lower/OpenACC/acc-reduction.f90 b/flang/test/Lower/OpenACC/acc-reduction.f90
index 2c79cacada050..b17cea99ae44a 100644
--- a/flang/test/Lower/OpenACC/acc-reduction.f90
+++ b/flang/test/Lower/OpenACC/acc-reduction.f90
@@ -910,8 +910,7 @@
 ! CHECK:               %[[DESIGNATE_1:.*]] = hlfir.designate %[[VAL_0]] (%[[VAL_3]], %[[VAL_2]])  : (!fir.ref<!fir.array<100x10xi32>>, index, index) -> !fir.ref<i32>
 ! CHECK:               %[[LOAD_0:.*]] = fir.load %[[DESIGNATE_0]] : !fir.ref<i32>
 ! CHECK:               %[[LOAD_1:.*]] = fir.load %[[DESIGNATE_1]] : !fir.ref<i32>
-! CHECK:               %[[CMPI_0:.*]] = arith.cmpi sgt, %[[LOAD_1]], %[[LOAD_0]] : i32
-! CHECK:               %[[SELECT_0:.*]] = arith.select %[[CMPI_0]], %[[LOAD_1]], %[[LOAD_0]] : i32
+! CHECK:               %[[SELECT_0:.*]] = arith.maxsi %[[LOAD_1]], %[[LOAD_0]] : i32
 ! CHECK:               hlfir.assign %[[SELECT_0]] to %[[DESIGNATE_1]] : i32, !fir.ref<i32>
 ! CHECK:             }
 ! CHECK:           }
@@ -929,8 +928,7 @@
 ! CHECK:         ^bb0(%[[VAL_0:.*]]: !fir.ref<i32>, %[[VAL_1:.*]]: !fir.ref<i32>):
 ! CHECK:           %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
 ! CHECK:           %[[LOAD_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<i32>
-! CHECK:           %[[CMPI_0:.*]] = arith.cmpi sgt, %[[LOAD_1]], %[[LOAD_0]] : i32
-! CHECK:           %[[SELECT_0:.*]] = arith.select %[[CMPI_0]], %[[LOAD_1]], %[[LOAD_0]] : i32
+! CHECK:           %[[SELECT_0:.*]] = arith.maxsi %[[LOAD_1]], %[[LOAD_0]] : i32
 ! CHECK:           hlfir.assign %[[SELECT_0]] to %[[VAL_0]] : i32, !fir.ref<i32>
 ! CHECK:           acc.yield %[[VAL_0]] : !fir.ref<i32>
 ! CHECK:         }
@@ -1023,8 +1021,7 @@
 ! CHECK:             %[[DESIGNATE_1:.*]] = hlfir.designate %[[VAL_0]] (%[[VAL_2]])  : (!fir.ref<!fir.array<100xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             %[[LOAD_0:.*]] = fir.load %[[DESIGNATE_0]] : !fir.ref<i32>
 ! CHECK:             %[[LOAD_1:.*]] = fir.load %[[DESIGNATE_1]] : !fir.ref<i32>
-! CHECK:             %[[CMPI_0:.*]] = arith.cmpi slt, %[[LOAD_1]], %[[LOAD_0]] : i32
-! CHECK:             %[[SELECT_0:.*]] = arith.select %[[CMPI_0]], %[[LOAD_1]], %[[LOAD_0]] : i32
+! CHECK:             %[[SELECT_0:.*]] = arith.minsi %[[LOAD_1]], %[[LOAD_0]] : i32
 ! CHECK:             hlfir.assign %[[SELECT_0]] to %[[DESIGNATE_1]] : i32, !fir.ref<i32>
 ! CHECK:           }
 ! CHECK:           acc.yield %[[VAL_0]] : !fir.ref<!fir.array<100xi32>>
@@ -1041,8 +1038,7 @@
 ! CHECK:         ^bb0(%[[VAL_0:.*]]: !fir.ref<i32>, %[[VAL_1:.*]]: !fir.ref<i32>):
 ! CHECK:           %[[LOAD_0:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
 ! CHECK:           %[[LOAD_1:.*]] = fir.load %[[VAL_0]] : !fir.ref<i32>
-! CHECK:           %[[CMPI_0:.*]] = arith.cmpi slt, %[[LOAD_1]], %[[LOAD_0]] : i32
-! CHECK:           %[[SELECT_0:.*]] = arith.select %[[CMPI_0]], %[[LOAD_1]], %[[LOAD_0]] : i32
+! CHECK:           %[[SELECT_0:.*]] = arith.minsi %[[LOAD_1]], %[[LOAD_0]] : i32
 ! CHECK:           hlfir.assign %[[SELECT_0]] to %[[VAL_0]] : i32, !fir.ref<i32>
 ! CHECK:           acc.yield %[[VAL_0]] : !fir.ref<i32>
 ! CHECK:         }
diff --git a/flang/test/Lower/OpenMP/atomic-update.f90 b/flang/test/Lower/OpenMP/atomic-update.f90
index 05adee312dd6a..03db8b104bfde 100644
--- a/flang/test/Lower/OpenMP/atomic-update.f90
+++ b/flang/test/Lower/OpenMP/atomic-update.f90
@@ -106,8 +106,7 @@ program OmpAtomicUpdate
 !CHECK:  %[[VAL_D_LOADED:.*]] = fir.load %[[VAL_D_DECLARE]]#0 : !fir.ref<i32>
 !CHECK: omp.atomic.update memory_order(relaxed) %[[VAL_Y_DECLARE]]#0 : !fir.ref<i32> {
 !CHECK: ^bb0(%[[ARG:.*]]: i32):
-!CHECK:  {{.*}} = arith.cmpi sgt, %[[ARG]], {{.*}} : i32
-!CHECK:  %[[TEMP:.*]] = arith.select {{.*}} : i32
+!CHECK:  %[[TEMP:.*]] = arith.maxsi {{.*}} : i32
 !CHECK:  omp.yield(%[[TEMP]] : i32)
 !CHECK: }
     !$omp atomic update relaxed
@@ -175,8 +174,7 @@ program OmpAtomicUpdate
 !CHECK:   %[[VAL_Z_LOADED:.*]] = fir.load %[[VAL_Z_DECLARE]]#0 : !fir.ref<i32>
 !CHECK:   omp.atomic.update %[[VAL_W_DECLARE]]#0 : !fir.ref<i32> {
 !CHECK:   ^bb0(%[[ARG_W:.*]]: i32):
-!CHECK:     %[[W_CMP:.*]] = arith.cmpi sgt, %[[ARG_W]], {{.*}} : i32
-!CHECK:     %[[WXYZ_MAX:.*]] = arith.select %[[W_CMP]], %[[ARG_W]], {{.*}} : i32
+!CHECK:     %[[WXYZ_MAX:.*]] = arith.maxsi %[[ARG_W]], {{.*}} : i32
 !CHECK:     omp.yield(%[[WXYZ_MAX]] : i32)
 !CHECK:   }
   !$omp atomic update
diff --git a/flang/test/Lower/OpenMP/minmax-optional-parameters.f90 b/flang/test/Lower/OpenMP/minmax-optional-parameters.f90
index 418a3cad8cdaf..6941d11a80ff1 100644
--- a/flang/test/Lower/OpenMP/minmax-optional-parameters.f90
+++ b/flang/test/Lower/OpenMP/minmax-optional-parameters.f90
@@ -42,20 +42,17 @@ subroutine f00(a, x, y)
 !CHECK: %[[V4:[0-9]+]] = fir.load %[[VAL_X]]#0 : !fir.ref<i32>
 !CHECK: %[[V5:[0-9]+]] = fir.load %[[VAL_X]]#0 : !fir.ref<i32>
 !CHECK: %[[V6:[0-9]+]] = fir.is_present %[[VAL_Y]]#0 : (!fir.ref<i32>) -> i1
-!CHECK: %[[V7:[0-9]+]] = arith.cmpi slt, %[[V4]], %[[V5]] : i32
-!CHECK: %[[V8:[0-9]+]] = arith.select %[[V7]], %[[V4]], %[[V5]] : i32
+!CHECK: %[[V8:[0-9]+]] = arith.minsi %[[V4]], %[[V5]] : i32
 !CHECK: %[[V9:[0-9]+]] = fir.if %[[V6]] -> (i32) {
 !CHECK:   %[[V10:[0-9]+]] = fir.load %[[VAL_Y]]#0 : !fir.ref<i32>
-!CHECK:   %[[V11:[0-9]+]] = arith.cmpi slt, %[[V8]], %[[V10]] : i32
-!CHECK:   %[[V12:[0-9]+]] = arith.select %[[V11]], %[[V8]], %[[V10]] : i32
+!CHECK:   %[[V12:[0-9]+]] = arith.minsi %[[V8]], %[[V10]] : i32
 !CHECK:   fir.result %[[V12]] : i32
 !CHECK: } else {
 !CHECK:   fir.result %[[V8]] : i32
 !CHECK: }
 !CHECK: omp.atomic.update memory_order(relaxed) %[[VAL_A]]#0 : !fir.ref<i32> {
 !CHECK: ^bb0(%[[ARG:[a-z0-9]+]]: i32):
-!CHECK:   %[[V10:[0-9]+]] = arith.cmpi slt, %[[ARG]], %[[V9]] : i32
-!CHECK:   %[[V11:[0-9]+]] = arith.select %[[V10]], %[[ARG]], %[[V9]] : i32
+!CHECK:   %[[V11:[0-9]+]] = arith.minsi %[[ARG]], %[[V9]] : i32
 !CHECK:   omp.yield(%[[V11]] : i32)
 !CHECK: }
 
diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90
index ff70acbb10e32..7e481a9264117 100644
--- a/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90
+++ b/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90
@@ -103,8 +103,7 @@ end module maxtype_mod
 !CHECK:    %[[LHS_MAXVAL:.*]] = fir.load %[[LHS_DESIGNATE_MAXVAL]] : !fir.ref<i32>
 !CHECK:    %[[RHS_DESIGNATE_MAXVAL:.*]] = hlfir.designate %[[RHS_DECL]]#0{"maxval"}   : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref<i32>
 !CHECK:    %[[RHS_MAXVAL:.*]] = fir.load %[[RHS_DESIGNATE_MAXVAL]] : !fir.ref<i32>
-!CHECK:    %[[CMP:.*]] = arith.cmpi sgt, %[[LHS_MAXVAL]], %[[RHS_MAXVAL]] : i32
-!CHECK:    %[[MAX_VAL:.*]] = arith.select %[[CMP]], %[[LHS_MAXVAL]], %[[RHS_MAXVAL]] : i32
+!CHECK:    %[[MAX_VAL:.*]] = arith.maxsi %[[LHS_MAXVAL]], %[[RHS_MAXVAL]] : i32
 !CHECK:    %[[RESULT_DESIGNAGE_MAXVAL:.*]] = hlfir.designate %[[RESULT_DECL]]#0{"maxval"}   : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref<i32>
 !CHECK:    hlfir.assign %[[MAX_VAL]] to %[[RESULT_DESIGNAGE_MAXVAL]] : i32, !fir.ref<i32>
 !CHECK:    %[[RESULT:.*]] = fir.load %[[RESULT_DECL]]#0 : !fir.ref<[[MAXTYPE]]>
diff --git a/flang/test/Lower/OpenMP/reduction-array-intrinsic.f90 b/flang/test/Lower/OpenMP/reduction-array-intrinsic.f90
index 779322712dbfe..f7bc03b336d61 100644
--- a/flang/test/Lower/OpenMP/reduction-array-intrinsic.f90
+++ b/flang/test/Lower/OpenMP/reduction-array-intrinsic.f90
@@ -85,8 +85,7 @@ subroutine max_array_reduction(l, r)
 ! CHECK-DAG:               %[[VAL_20:.*]] = fir.load %[[VAL_19]] : !fir.ref<i32>
 ! CHECK-DAG:               %[[VAL_21:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_13]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
 ! CHECK-DAG:               %[[VAL_22:.*]] = fir.load %[[VAL_21]] : !fir.ref<i32>
-! CHECK:               %[[VAL_23:.*]] = arith.cmpi sgt, %[[VAL_20]], %[[VAL_22]] : i32
-! CHECK:               %[[VAL_24:.*]] = arith.select %[[VAL_23]], %[[VAL_20]], %[[VAL_22]] : i32
+! CHECK:               %[[VAL_24:.*]] = arith.maxsi %[[VAL_20]], %[[VAL_22]] : i32
 ! CHECK:               hlfir.yield_element %[[VAL_24]] : i32
 ! CHECK:             }
 ! CHECK:             %[[VAL_25:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<!fir.box<!fir.array<?xi32>>>
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90
index ed81577ecce16..630bd46863c0e 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90
@@ -246,8 +246,7 @@ program reduce15
 ! CHECK-DAG:                   %[[VAL_81:.*]] = arith.addi %[[VAL_69]], %[[VAL_80]] : index
 ! CHECK-DAG:                   %[[VAL_82:.*]] = hlfir.designate %[[VAL_67]] (%[[VAL_81]])  : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
 ! CHECK-DAG:                   %[[VAL_83:.*]] = fir.load %[[VAL_82]] : !fir.ref<i32>
-! CHECK:                   %[[VAL_84:.*]] = arith.cmpi sgt, %[[VAL_76]], %[[VAL_83]] : i32
-! CHECK:                   %[[VAL_85:.*]] = arith.select %[[VAL_84]], %[[VAL_76]], %[[VAL_83]] : i32
+! CHECK:                   %[[VAL_85:.*]] = arith.maxsi %[[VAL_76]], %[[VAL_83]] : i32
 ! CHECK:                   hlfir.yield_element %[[VAL_85]] : i32
 ! CHECK:                 }
 ! CHECK:                 hlfir.assign %[[VAL_68]] to %[[VAL_62]]#0 realloc : !hlfir.expr<?xi32>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
@@ -287,8 +286,7 @@ program reduce15
 ! CHECK-DAG:               %[[VAL_113:.*]] = arith.addi %[[VAL_101]], %[[VAL_112]] : index
 ! CHECK-DAG:               %[[VAL_114:.*]] = hlfir.designate %[[VAL_99]] (%[[VAL_113]])  : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
 ! CHECK-DAG:               %[[VAL_115:.*]] = fir.load %[[VAL_114]] : !fir.ref<i32>
-! CHECK:                   %[[VAL_116:.*]] = arith.cmpi slt, %[[VAL_108]], %[[VAL_115]] : i32
-! CHECK:                   %[[VAL_117:.*]] = arith.select %[[VAL_116]], %[[VAL_108]], %[[VAL_115]] : i32
+! CHECK:                   %[[VAL_117:.*]] = arith.minsi %[[VAL_108]], %[[VAL_115]] : i32
 ! CHECK:                   hlfir.yield_element %[[VAL_117]] : i32
 ! CHECK:                 }
 ! CHECK:                 hlfir.assign %[[VAL_100]] to %[[VAL_94]]#0 realloc : !hlfir.expr<?xi32>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90
index 0438e19f34391..382f4d625a762 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90
@@ -2,8 +2,7 @@
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --force-byref-reduction -o - %s 2>&1 | FileCheck %s
 
 ! CHECK: omp.wsloop private({{.*}}) reduction(byref @max_byref_i32
-! CHECK: arith.cmpi sgt
-! CHECK: arith.select
+! CHECK: arith.maxsi
 
 module m1
   intrinsic max
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90
index 66c75bbe38f10..039ba57b840cc 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90
@@ -2,8 +2,7 @@
 ! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
 
 ! CHECK: omp.wsloop private({{.*}}) reduction(@max_i32
-! CHECK: arith.cmpi sgt
-! CHECK: arith.select
+! CHECK: arith.maxsi
 
 module m1
   intrinsic max
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90
index 73a8885fa3124..5b5beec633c36 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90
@@ -58,8 +58,7 @@
 ! CHECK-DAG:                 %[[VAL_17:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_16]])  : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_18:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_19:.*]] = fir.load %[[VAL_17]] : !fir.ref<i32>
-! CHECK:                 %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_18]], %[[VAL_19]] : i32
-! CHECK:                 %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_18]], %[[VAL_19]] : i32
+! CHECK:                 %[[VAL_21:.*]] = arith.maxsi %[[VAL_18]], %[[VAL_19]] : i32
 ! CHECK:                 hlfir.assign %[[VAL_21]] to %[[VAL_14]]#0 : i32, !fir.ref<i32>
 ! CHECK:                 omp.yield
 ! CHECK:             omp.terminator
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max.f90
index cebd779dee61f..3fb5bf7752c75 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-max.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-max.f90
@@ -48,8 +48,7 @@
 ! CHECK-DAG:                 %[[VAL_17:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_16]])  : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_18:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_19:.*]] = fir.load %[[VAL_17]] : !fir.ref<i32>
-! CHECK:                 %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_18]], %[[VAL_19]] : i32
-! CHECK:                 %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_18]], %[[VAL_19]] : i32
+! CHECK:                 %[[VAL_21:.*]] = arith.maxsi %[[VAL_18]], %[[VAL_19]] : i32
 ! CHECK:                 hlfir.assign %[[VAL_21]] to %[[VAL_14]]#0 : i32, !fir.ref<i32>
 ! CHECK:                 omp.yield
 ! CHECK:             omp.terminator
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90
index 1a6bc37168557..dbf0720a0d6b8 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90
@@ -58,8 +58,7 @@
 ! CHECK-DAG:                 %[[VAL_17:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_16]])  : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_18:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_19:.*]] = fir.load %[[VAL_17]] : !fir.ref<i32>
-! CHECK:                 %[[VAL_20:.*]] = arith.cmpi slt, %[[VAL_18]], %[[VAL_19]] : i32
-! CHECK:                 %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_18]], %[[VAL_19]] : i32
+! CHECK:                 %[[VAL_21:.*]] = arith.minsi %[[VAL_18]], %[[VAL_19]] : i32
 ! CHECK:                 hlfir.assign %[[VAL_21]] to %[[VAL_14]]#0 : i32, !fir.ref<i32>
 ! CHECK:                 omp.yield
 ! CHECK:             omp.terminator
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-min.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-min.f90
index b3a899d3b70ba..4b8b059504fc5 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-min.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-min.f90
@@ -48,8 +48,7 @@
 ! CHECK-DAG:                 %[[VAL_17:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_16]])  : (!fir.box<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_18:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref<i32>
 ! CHECK-DAG:                 %[[VAL_19:.*]] = fir.load %[[VAL_17]] : !fir.ref<i32>
-! CHECK:                 %[[VAL_20:.*]] = arith.cmpi slt, %[[VAL_18]], %[[VAL_19]] : i32
-! CHECK:                 %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_18]], %[[VAL_19]] : i32
+! CHECK:                 %[[VAL_21:.*]] = arith.minsi %[[VAL_18]], %[[VAL_19]] : i32
 ! CHECK:                 hlfir.assign %[[VAL_21]] to %[[VAL_14]]#0 : i32, !fir.ref<i32>
 ! CHECK:                 omp.yield
 ! CHECK:             omp.terminator
diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90
index 66229259adf82..5301a6f04a2a6 100644
--- a/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90
+++ b/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90
@@ -57,7 +57,7 @@
 !CHECK:          %[[RES_Y:.+]] = arith.addf %[[LPRV_Y]], %{{.+}} : f32
 !CHECK:          hlfir.assign %[[RES_Y]] to %[[PRV_Y_DECL]]#0 : f32, !fir.ref<f32>
 !CHECK:          %[[LPRV_Z:.+]] = fir.load %[[PRV_Z_DECL]]#0 : !fir.ref<i32>
-!CHECK:          %[[RES_Z:.+]] = arith.select %{{.+}}, %[[LPRV_Z]], %{{.+}} : i32
+!CHECK:          %[[RES_Z:.+]] = arith.minsi %[[LPRV_Z]], %{{.+}} : i32
 !CHECK:          hlfir.assign %[[RES_Z]] to %[[PRV_Z_DECL]]#0 : i32, !fir.ref<i32>
 !CHECK:          omp.yield
 !CHECK:        }
diff --git a/flang/test/Lower/array-elemental-calls-2.f90 b/flang/test/Lower/array-elemental-calls-2.f90
index 30e2cf88d1195..86374de477497 100644
--- a/flang/test/Lower/array-elemental-calls-2.f90
+++ b/flang/test/Lower/array-elemental-calls-2.f90
@@ -114,8 +114,7 @@ subroutine check_exteremum()
 ! CHECK:    %[[VAL_38:.*]] = hlfir.designate %{{.*}} (%[[ARG0]])  : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
 ! CHECK:    %[[VAL_39:.*]] = fir.load %[[VAL_37]] : !fir.ref<i32>
 ! CHECK:    %[[VAL_40:.*]] = fir.load %[[VAL_38]] : !fir.ref<i32>
-! CHECK:    %[[VAL_41:.*]] = arith.cmpi slt, %[[VAL_39]], %[[VAL_40]] : i32
-! CHECK:    %[[VAL_42:.*]] = arith.select %[[VAL_41]], %[[VAL_39]], %[[VAL_40]] : i32
+! CHECK:    %[[VAL_42:.*]] = arith.minsi %[[VAL_39]], %[[VAL_40]] : i32
 ! CHECK:    hlfir.yield_element %[[VAL_42]] : i32
 ! CHECK:  }
 ! CHECK:  %[[VAL_30:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> {

>From f74e1f1835e02783ce45d59bcb0b21ed2f86be63 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Fri, 13 Mar 2026 11:38:41 -0700
Subject: [PATCH 2/5] Added conversions for unsigned types.

---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index f421bddebea8a..d800b98700189 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -8783,11 +8783,23 @@ static mlir::Value genExtremumResult(mlir::Location loc,
     if (mlir::isa<mlir::IndexType>(type))
       TODO(loc, "extremum for index type");
 
+    mlir::Value cmpLeft = left;
+    mlir::Value cmpRight = right;
     if (type.isUnsignedInteger()) {
+      // arith.maxui/minui operands must have singless type.
+      mlir::Type signlessType = mlir::IntegerType::get(
+          builder.getContext(), type.getIntOrFloatBitWidth(),
+          mlir::IntegerType::SignednessSemantics::Signless);
+      left = builder.createConvert(loc, signlessType, left);
+      right = builder.createConvert(loc, signlessType, right);
+
+      mlir::Value result;
       if constexpr (isMax)
-        return mlir::arith::MaxUIOp::create(builder, loc, left, right);
+        result = mlir::arith::MaxUIOp::create(builder, loc, left, right);
       else
-        return mlir::arith::MinUIOp::create(builder, loc, left, right);
+        result = mlir::arith::MinUIOp::create(builder, loc, left, right);
+
+      return builder.createConvert(loc, type, result);
     } else {
       if constexpr (isMax)
         return mlir::arith::MaxSIOp::create(builder, loc, left, right);

>From 6e40b17e52df630b9c3fb61366c69419d44cd190 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Fri, 13 Mar 2026 11:57:45 -0700
Subject: [PATCH 3/5] Unused vars.

---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index d800b98700189..d72dc8cba327b 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -8783,8 +8783,6 @@ static mlir::Value genExtremumResult(mlir::Location loc,
     if (mlir::isa<mlir::IndexType>(type))
       TODO(loc, "extremum for index type");
 
-    mlir::Value cmpLeft = left;
-    mlir::Value cmpRight = right;
     if (type.isUnsignedInteger()) {
       // arith.maxui/minui operands must have singless type.
       mlir::Type signlessType = mlir::IntegerType::get(

>From cba93557080bd0366051c0bb4fdf24d0b51e21cd Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Mon, 16 Mar 2026 13:45:39 -0700
Subject: [PATCH 4/5] Added lowering tests for unsigned types. Unified code
 between max/min and maxval/minval.

---
 .../Transforms/SimplifyHLFIRIntrinsics.cpp    | 44 ++--------------
 flang/test/Lower/fp-maxmin-behavior.f90       | 52 +++++++++++++++----
 2 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp b/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp
index f47353dc30f64..35141ff8d0bf7 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp
@@ -802,6 +802,7 @@ class MinMaxvalAsElementalConverter
     this->checkReductions(currentValue);
     llvm::SmallVector<mlir::Value> result;
     fir::FirOpBuilder &builder = this->builder;
+    builder.setFPMaxminBehavior(fpMaxminBehavior);
     mlir::Location loc = this->loc;
     hlfir::Entity elementValue =
         hlfir::loadElementAt(loc, builder, array, oneBasedIndices);
@@ -893,45 +894,10 @@ class MinMaxvalAsElementalConverter
     assert(!useIsFirst() &&
            "unordered max/min reduction must not use first predicate");
 
-    if (mlir::isa<fir::CharacterType>(this->getSourceElementType()))
-      TODO(loc, "max/minval with CHARACTER type");
-
-    if (auto intType =
-            mlir::dyn_cast<mlir::IntegerType>(this->getSourceElementType())) {
-      if (intType.isUnsigned())
-        TODO(loc, "max/minval with UNSIGNED type");
-
-      if constexpr (isMax)
-        return mlir::arith::MaxSIOp::create(builder, loc, elementValue,
-                                            currentMinMax);
-      else
-        return mlir::arith::MinSIOp::create(builder, loc, elementValue,
-                                            currentMinMax);
-    }
-
-    if (fpMaxminBehavior == Fortran::common::FPMaxminBehavior::Extremum) {
-      if constexpr (isMax)
-        return mlir::arith::MaximumFOp::create(builder, loc, elementValue,
-                                               currentMinMax);
-      else
-        return mlir::arith::MinimumFOp::create(builder, loc, elementValue,
-                                               currentMinMax);
-    }
-
-    if (fpMaxminBehavior == Fortran::common::FPMaxminBehavior::ExtremeNum ||
-        (fpMaxminBehavior == Fortran::common::FPMaxminBehavior::Portable &&
-         mlir::arith::bitEnumContainsAll(
-             this->getFastMath(), mlir::arith::FastMathFlags::nnan |
-                                      mlir::arith::FastMathFlags::nsz))) {
-      if constexpr (isMax)
-        return mlir::arith::MaxNumFOp::create(builder, loc, elementValue,
-                                              currentMinMax);
-      else
-        return mlir::arith::MinNumFOp::create(builder, loc, elementValue,
-                                              currentMinMax);
-    }
-
-    llvm_unreachable("unhandled unordered max/min reduction");
+    if constexpr (isMax)
+      return fir::genMax(builder, loc, {elementValue, currentMinMax});
+    else
+      return fir::genMin(builder, loc, {elementValue, currentMinMax});
   }
 
   std::size_t getNumReductions() const { return useIsFirst() ? 2 : 1; }
diff --git a/flang/test/Lower/fp-maxmin-behavior.f90 b/flang/test/Lower/fp-maxmin-behavior.f90
index 7b668f3b50857..9d9eb9b2d9625 100644
--- a/flang/test/Lower/fp-maxmin-behavior.f90
+++ b/flang/test/Lower/fp-maxmin-behavior.f90
@@ -3,19 +3,19 @@
 ! extremenum uses arith.maxnumf/minnumf; portable with -fno-signed-zeros -menable-no-nans uses maxnumf/minnumf.
 
 ! bbc: legacy, extremum, extremenum
-! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s -check-prefix=LEGACY
-! RUN: bbc -emit-hlfir -ffp-maxmin-behavior=legacy -o - %s 2>&1 | FileCheck %s -check-prefix=LEGACY
-! RUN: bbc -emit-hlfir -ffp-maxmin-behavior=extremum -o - %s 2>&1 | FileCheck %s -check-prefix=EXTREMUM
-! RUN: bbc -emit-hlfir -ffp-maxmin-behavior=extremenum -o - %s 2>&1 | FileCheck %s -check-prefix=EXTREMENUM
+! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,LEGACY
+! RUN: bbc -emit-hlfir -ffp-maxmin-behavior=legacy -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,LEGACY
+! RUN: bbc -emit-hlfir -ffp-maxmin-behavior=extremum -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,EXTREMUM
+! RUN: bbc -emit-hlfir -ffp-maxmin-behavior=extremenum -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,EXTREMENUM
 
 ! flang -fc1: legacy, extremum, extremenum
-! RUN: %flang_fc1 -emit-hlfir -o - %s 2>&1 | FileCheck %s -check-prefix=LEGACY
-! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=legacy -o - %s 2>&1 | FileCheck %s -check-prefix=LEGACY
-! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=extremum -o - %s 2>&1 | FileCheck %s -check-prefix=EXTREMUM
-! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=extremenum -o - %s 2>&1 | FileCheck %s -check-prefix=EXTREMENUM
+! RUN: %flang_fc1 -emit-hlfir -funsigned -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,LEGACY
+! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=legacy -funsigned -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,LEGACY
+! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=extremum -funsigned -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,EXTREMUM
+! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=extremenum -funsigned -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,EXTREMENUM
 
 ! portable with -fno-signed-zeros -menable-no-nans => maxnumf/minnumf (flang -fc1 only; bbc does not expose these flags)
-! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=portable -fno-signed-zeros -menable-no-nans -o - %s 2>&1 | FileCheck %s -check-prefix=PORTABLE-NANNSZ
+! RUN: %flang_fc1 -emit-hlfir -ffp-maxmin-behavior=portable -funsigned -fno-signed-zeros -menable-no-nans -o - %s 2>&1 | FileCheck %s -check-prefix=ALL,PORTABLE-NANNSZ
 
 subroutine real_max(a, b, r)
   real :: a, b, r
@@ -50,3 +50,37 @@ subroutine real_min(a, b, r)
 
 ! PORTABLE-NANNSZ-LABEL: func.func @_QPreal_min(
 ! PORTABLE-NANNSZ: arith.minnumf
+
+subroutine signed_max(a, b, r)
+  integer :: a, b, r
+  r = max(a, b)
+end subroutine signed_max
+! ALL-LABEL: func.func @_QPsigned_max(
+! ALL: arith.maxsi
+
+subroutine unsigned_max(a, b, r)
+  unsigned :: a, b, r
+  r = max(a, b)
+end subroutine unsigned_max
+! ALL-LABEL: func.func @_QPunsigned_max(
+! ALL: %[[CVT1:.*]] = fir.convert %{{.*}} : (ui32) -> i32
+! ALL: %[[CVT2:.*]] = fir.convert %{{.*}} : (ui32) -> i32
+! ALL: %[[MAX:.*]] = arith.maxui %[[CVT1]], %[[CVT2]] : i32
+! ALL: fir.convert %[[MAX]] : (i32) -> ui32
+
+subroutine signed_min(a, b, r)
+  integer :: a, b, r
+  r = min(a, b)
+end subroutine signed_min
+! ALL-LABEL: func.func @_QPsigned_min(
+! ALL: arith.minsi
+
+subroutine unsigned_min(a, b, r)
+  unsigned :: a, b, r
+  r = min(a, b)
+end subroutine unsigned_min
+! ALL-LABEL: func.func @_QPunsigned_min(
+! ALL: %[[CVT1:.*]] = fir.convert %{{.*}} : (ui32) -> i32
+! ALL: %[[CVT2:.*]] = fir.convert %{{.*}} : (ui32) -> i32
+! ALL: %[[MIN:.*]] = arith.minui %[[CVT1]], %[[CVT2]] : i32
+! ALL: fir.convert %[[MIN]] : (i32) -> ui32

>From d31e4c1b1674f4f5d1c647feff0733f432f9861d Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Tue, 17 Mar 2026 08:11:54 -0700
Subject: [PATCH 5/5] Added a comment.

---
 .../Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp    | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp b/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp
index 35141ff8d0bf7..7ff9dc61110d3 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp
@@ -382,6 +382,10 @@ template <bool IS_MAX>
 static mlir::Value
 genMinMaxComparison(mlir::Location loc, fir::FirOpBuilder &builder,
                     mlir::Value elem, mlir::Value reduction) {
+  // TODO: there is some opportunity to generalize this code with
+  // IntrinsicLibrary::genExtremum(), but one have to be careful
+  // to preserve the NaNs behavior (when needed) that is handled
+  // here with the three FP comparisons.
   if (mlir::isa<mlir::FloatType>(reduction.getType())) {
     // For FP reductions we want the first smallest value to be used, that
     // is not NaN. A OGL/OLT condition will usually work for this unless all



More information about the flang-commits mailing list