[flang-commits] [flang] [flang] Guard absent optional operands in elemental character MIN/MAX (PR #191244)

Sairudra More via flang-commits flang-commits at lists.llvm.org
Fri Apr 10 21:40:48 PDT 2026


https://github.com/Saieiei updated https://github.com/llvm/llvm-project/pull/191244

>From b23993eb475f81e6c315364b8972bce41218007e Mon Sep 17 00:00:00 2001
From: Sairudra More <moresair at pe31.hpc.amslabs.hpecorp.net>
Date: Fri, 10 Apr 2026 23:40:01 -0500
Subject: [PATCH] [flang] Route elemental CHARACTER MIN/MAX OPTIONAL cases
 through custom lowering

genHLFIRIntrinsicRefCore was bypassing the custom optional-handling path used by the other intrinsic lowering entry points. As a result, elemental CHARACTER MIN/MAX with dynamically optional arguments could reach HlfirCharExtremumLowering and produce bad code instead of taking the existing custom-lowering path.

Route these cases through genCustomIntrinsicRefCore so they hit the existing TODO for CHARACTER MIN/MAX with dynamically optional arguments rather than silently lowering incorrectly. Also remove the executable lit test per review and update tests to reflect the corrected dispatch.
---
 flang/lib/Lower/ConvertCall.cpp               |  8 +++
 .../HLFIR/elemental-character-min-max.f90     | 57 -------------------
 2 files changed, 8 insertions(+), 57 deletions(-)

diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index ea65a49355330..54d08bb420755 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -2342,6 +2342,14 @@ static std::optional<hlfir::EntityWithAttributes> genHLFIRIntrinsicRefCore(
     const Fortran::evaluate::SpecificIntrinsic *intrinsic,
     const fir::IntrinsicHandlerEntry &intrinsicEntry,
     CallContext &callContext) {
+  // Delegate intrinsics with custom optional handling to
+  // genCustomIntrinsicRefCore before attempting any HLFIR op lowering. This
+  // ensures consistent dispatch symmetry with genIntrinsicRefCore and
+  // genIntrinsicRef, both of which check for custom optional handling before
+  // reaching the HLFIR intrinsic path.
+  if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling(
+                       callContext.procRef, *intrinsic, callContext.converter))
+    return genCustomIntrinsicRefCore(loweredActuals, intrinsic, callContext);
   // Try lowering transformational intrinsic ops to HLFIR ops if enabled
   // (transformational always have a result type)
   if (useHlfirIntrinsicOps && callContext.resultType) {
diff --git a/flang/test/Lower/HLFIR/elemental-character-min-max.f90 b/flang/test/Lower/HLFIR/elemental-character-min-max.f90
index fc149f0759188..5df54a9262c5c 100644
--- a/flang/test/Lower/HLFIR/elemental-character-min-max.f90
+++ b/flang/test/Lower/HLFIR/elemental-character-min-max.f90
@@ -70,60 +70,3 @@ subroutine test_elemental_char_min_three(a, b, c, res)
 ! CHECK:             %{{.*}} = hlfir.char_extremum min, %{{.*}}, %{{.*}}, %{{.*}} :
 ! CHECK:             hlfir.yield_element
 ! CHECK:           }
-
-! Test elemental character MIN with an optional dummy argument of fixed length.
-! The result length must guard the optional argument's length with fir.if so
-! genCharLength is not called on an absent optional (unsafe for assumed length).
-subroutine test_elemental_char_min_optional(a, b, c, res)
-  character(5) :: a(10), b(10), res(10)
-  character(5), optional :: c(10)
-  res = min(a, b, c)
-end subroutine
-! CHECK-LABEL:   func.func @_QPtest_elemental_char_min_optional(
-! CHECK:           %[[C5_A:.*]] = arith.constant 5 : index
-! CHECK:           %[[A:.*]]:2 = hlfir.declare {{.*}}Ea"
-! CHECK:           %[[C5_B:.*]] = arith.constant 5 : index
-! CHECK:           %[[B:.*]]:2 = hlfir.declare {{.*}}Eb"
-! CHECK:           %[[C5_C:.*]] = arith.constant 5 : index
-! CHECK:           %[[C:.*]]:2 = hlfir.declare {{.*}}Ec"
-! CHECK:           %[[IS_PRESENT:.*]] = fir.is_present %[[C]]#0
-! CHECK:           %[[CMP1:.*]] = arith.cmpi sgt, %[[C5_B]], %[[C5_A]] : index
-! CHECK:           %[[MAX1:.*]] = arith.select %[[CMP1]], %[[C5_B]], %[[C5_A]] : index
-! CHECK:           %[[C0:.*]] = arith.constant 0 : index
-! CHECK:           %[[OPT_LEN:.*]] = fir.if %[[IS_PRESENT]] -> (index) {
-! CHECK:             fir.result %[[C5_C]] : index
-! CHECK:           } else {
-! CHECK:             fir.result %[[C0]] : index
-! CHECK:           }
-! CHECK:           %[[CMP2:.*]] = arith.cmpi sgt, %[[OPT_LEN]], %[[MAX1]] : index
-! CHECK:           %[[RESULT_LEN:.*]] = arith.select %[[CMP2]], %[[OPT_LEN]], %[[MAX1]] : index
-! CHECK:           %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} typeparams %[[RESULT_LEN]]
-
-! Test elemental character MIN with an assumed-length optional dummy argument.
-! genCharLength reads from the descriptor, so it must be guarded with fir.if
-! to avoid reading an invalid descriptor when the argument is absent.
-subroutine test_elemental_char_min_assumed_optional(a, b, c, res)
-  character(*), intent(in) :: a(:), b(:)
-  character(*), intent(in), optional :: c(:)
-  character(*), intent(out) :: res(:)
-  res = min(a, b, c)
-end subroutine
-! CHECK-LABEL:   func.func @_QPtest_elemental_char_min_assumed_optional(
-! CHECK:           %[[A:.*]]:2 = hlfir.declare {{.*}}Ea"
-! CHECK:           %[[B:.*]]:2 = hlfir.declare {{.*}}Eb"
-! CHECK:           %[[C:.*]]:2 = hlfir.declare {{.*}}Ec"
-! CHECK:           %[[IS_PRESENT:.*]] = fir.is_present %[[C]]#0
-! CHECK:           %[[LEN_A:.*]] = fir.box_elesize %[[A]]#1
-! CHECK:           %[[LEN_B:.*]] = fir.box_elesize %[[B]]#1
-! CHECK:           %[[CMP1:.*]] = arith.cmpi sgt, %[[LEN_B]], %[[LEN_A]] : index
-! CHECK:           %[[MAX1:.*]] = arith.select %[[CMP1]], %[[LEN_B]], %[[LEN_A]] : index
-! CHECK:           %[[C0:.*]] = arith.constant 0 : index
-! CHECK:           %[[OPT_LEN:.*]] = fir.if %[[IS_PRESENT]] -> (index) {
-! CHECK:             %[[LEN_C:.*]] = fir.box_elesize %[[C]]#1
-! CHECK:             fir.result %[[LEN_C]] : index
-! CHECK:           } else {
-! CHECK:             fir.result %[[C0]] : index
-! CHECK:           }
-! CHECK:           %[[CMP2:.*]] = arith.cmpi sgt, %[[OPT_LEN]], %[[MAX1]] : index
-! CHECK:           %[[RESULT_LEN:.*]] = arith.select %[[CMP2]], %[[OPT_LEN]], %[[MAX1]] : index
-! CHECK:           %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} typeparams %[[RESULT_LEN]] unordered



More information about the flang-commits mailing list