[flang-commits] [flang] [flang] Don't do actual concatenation when computing LEN() of concatenated strings (PR #180676)

Eugene Epshteyn via flang-commits flang-commits at lists.llvm.org
Mon Feb 9 21:05:59 PST 2026


https://github.com/eugeneepshteyn created https://github.com/llvm/llvm-project/pull/180676

For cases like the following don't actually compute concatenation of
`str // "abc"`, because we only need final length:
```
  character(len=*), intent(in) :: str
  character(len=len(str // "abc")) :: res
```
For such cases, don't emit hlfir.concat.

>From 77d9b3bcadd381918d34953e4f2ac450954435e1 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Mon, 9 Feb 2026 23:52:57 -0500
Subject: [PATCH 1/2] [flang] Don't do actual concatenation when computing
 LEN() of concatenated strings

For cases like the following don't actually compute concatenation of
`str // "abc"`, because we only need final length:
```
  character(len=*), intent(in) :: str
  character(len=len(str // "abc")) :: res
```
For such cases, don't emit hlfir.concat.
---
 flang/lib/Lower/HlfirIntrinsics.cpp           | 24 +++++++++
 .../Lower/HLFIR/assumed-rank-inquiries.f90    |  2 +-
 .../elemental-result-length-len-folding.f90   | 54 +++++++++++++++++++
 3 files changed, 79 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90

diff --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp
index 27c8bb87f7542..8fa40ff788d09 100644
--- a/flang/lib/Lower/HlfirIntrinsics.cpp
+++ b/flang/lib/Lower/HlfirIntrinsics.cpp
@@ -220,6 +220,14 @@ class HlfirIndexLowering : public HlfirTransformationalIntrinsic {
             mlir::Type stmtResultType) override;
 };
 
+struct HlfirLenLowering : public HlfirTransformationalIntrinsic {
+  using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;
+  mlir::Value
+  lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,
+            const fir::IntrinsicArgumentLoweringRules *argLowering,
+            mlir::Type stmtResultType) override;
+};
+
 } // namespace
 
 mlir::Value HlfirTransformationalIntrinsic::loadBoxAddress(
@@ -558,6 +566,19 @@ mlir::Value HlfirIndexLowering::lowerImpl(
   return result;
 }
 
+mlir::Value HlfirLenLowering::lowerImpl(
+    const Fortran::lower::PreparedActualArguments &loweredActuals,
+    const fir::IntrinsicArgumentLoweringRules *argLowering,
+    mlir::Type stmtResultType) {
+  // LEN (STRING [, KIND])
+  assert((loweredActuals.size() == 1 || loweredActuals.size() == 2) &&
+      loweredActuals[0].has_value());
+  Fortran::lower::PreparedActualArgument &strArg =
+      const_cast<Fortran::lower::PreparedActualArgument &>(*loweredActuals[0]);
+  return builder.createConvert(
+      loc, stmtResultType, strArg.genCharLength(loc, builder));
+}
+
 std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
     fir::FirOpBuilder &builder, mlir::Location loc, const std::string &name,
     const Fortran::lower::PreparedActualArguments &loweredActuals,
@@ -615,6 +636,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
   if (name == "index")
     return HlfirIndexLowering{builder, loc}.lower(loweredActuals, argLowering,
                                                   stmtResultType);
+  if (name == "len")
+    return HlfirLenLowering{builder, loc}.lower(loweredActuals, argLowering,
+                                                stmtResultType);
 
   if (mlir::isa<fir::CharacterType>(stmtResultType)) {
     if (name == "min")
diff --git a/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90 b/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90
index fcca1733dc639..5b49acc4c3d46 100644
--- a/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90
+++ b/flang/test/Lower/HLFIR/assumed-rank-inquiries.f90
@@ -166,7 +166,7 @@ subroutine c_loc_2(x)
 ! CHECK-SAME:                             %[[VAL_0:.*]]: !fir.box<!fir.array<*:!fir.char<1,?>>> {fir.bindc_name = "x"}) {
 ! CHECK:           %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
 ! CHECK:           %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] arg {{[0-9]+}} {uniq_name = "_QFtest_len_1Ex"} : (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<*:!fir.char<1,?>>>, !fir.box<!fir.array<*:!fir.char<1,?>>>)
-! CHECK:           %[[VAL_3:.*]] = fir.box_elesize %[[VAL_2]]#0 : (!fir.box<!fir.array<*:!fir.char<1,?>>>) -> index
+! CHECK:           %[[VAL_3:.*]] = fir.box_elesize %[[VAL_2]]#1 : (!fir.box<!fir.array<*:!fir.char<1,?>>>) -> index
 ! CHECK:           %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (index) -> i32
 ! CHECK:           %[[VAL_5:.*]]:3 = hlfir.associate %[[VAL_4]] {adapt.valuebyref} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
 ! CHECK:           fir.call @_QPtakes_integer(%[[VAL_5]]#0) fastmath<contract> : (!fir.ref<i32>) -> ()
diff --git a/flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90 b/flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90
new file mode 100644
index 0000000000000..c59a31b3b21ad
--- /dev/null
+++ b/flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90
@@ -0,0 +1,54 @@
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
+
+! Test that LEN intrinsic in elemental function result specification expression
+! is lowered efficiently in HLFIR, especially when it involves expressions
+! like concatenation that can be folded or handled without materialization.
+
+elemental function add_suffix(str) result(res)
+  character(len=*), intent(in) :: str
+  character(len=len(str // "abc")) :: res
+  res = str // "xyz"
+end function
+
+! CHECK-LABEL: func.func @_QPadd_suffix(
+! CHECK:         hlfir.declare {{.*}} "_QFadd_suffixEstr"
+! CHECK-NOT:     hlfir.concat
+! CHECK:         hlfir.declare {{.*}} "_QFadd_suffixEres"
+! CHECK:         hlfir.concat
+! CHECK:         hlfir.assign
+
+subroutine test_call(s, r)
+  character(*), intent(in) :: s(:)
+  character(*), intent(out) :: r(:)
+  interface
+    elemental function add_suffix(str) result(res)
+      character(len=*), intent(in) :: str
+      character(len=len(str // "abc")) :: res
+    end function
+  end interface
+  r = add_suffix(s)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_call(
+! CHECK:         hlfir.declare {{.*}} "_QFtest_callEs"
+! CHECK-NOT:     hlfir.concat
+! CHECK:         hlfir.elemental {{.*}} {
+! CHECK:           hlfir.designate
+! CHECK:           fir.alloca
+! CHECK:           hlfir.declare
+! CHECK:           fir.call @_QPadd_suffix
+! CHECK:         }
+
+subroutine test_trim(s, n)
+  character(*) :: s
+  integer :: n
+  n = len(trim(s))
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_trim(
+! CHECK:         hlfir.declare {{.*}} "_QFtest_trimEs"
+! CHECK:         %[[TRIM:.*]] = hlfir.char_trim
+! CHECK-NEXT:    %[[LEN:.*]] = hlfir.get_length %[[TRIM]]
+! CHECK-NEXT:    %[[LEN_I32:.*]] = fir.convert %[[LEN]] : (index) -> i32
+! CHECK-NEXT:    hlfir.assign %[[LEN_I32]] to {{.*}}
+! CHECK-NEXT:    hlfir.destroy %[[TRIM]]

>From dbfc18cc8d57917b152b614569a73c8be07ab1ea Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 10 Feb 2026 00:03:57 -0500
Subject: [PATCH 2/2] clang-format

---
 flang/lib/Lower/HlfirIntrinsics.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp
index 8fa40ff788d09..f63628d7824ff 100644
--- a/flang/lib/Lower/HlfirIntrinsics.cpp
+++ b/flang/lib/Lower/HlfirIntrinsics.cpp
@@ -572,11 +572,11 @@ mlir::Value HlfirLenLowering::lowerImpl(
     mlir::Type stmtResultType) {
   // LEN (STRING [, KIND])
   assert((loweredActuals.size() == 1 || loweredActuals.size() == 2) &&
-      loweredActuals[0].has_value());
+         loweredActuals[0].has_value());
   Fortran::lower::PreparedActualArgument &strArg =
       const_cast<Fortran::lower::PreparedActualArgument &>(*loweredActuals[0]);
-  return builder.createConvert(
-      loc, stmtResultType, strArg.genCharLength(loc, builder));
+  return builder.createConvert(loc, stmtResultType,
+                               strArg.genCharLength(loc, builder));
 }
 
 std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(



More information about the flang-commits mailing list