[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 22:23:13 PDT 2026
https://github.com/Saieiei updated https://github.com/llvm/llvm-project/pull/191244
>From 1f43adb1f3b72a21f79fc8334e87109b16d15868 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