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

via flang-commits flang-commits at lists.llvm.org
Tue Feb 10 18:02:07 PST 2026


Author: Eugene Epshteyn
Date: 2026-02-10T21:02:02-05:00
New Revision: 50746f28f12d7b28fdaa3fc0de5822ea42a0d5a4

URL: https://github.com/llvm/llvm-project/commit/50746f28f12d7b28fdaa3fc0de5822ea42a0d5a4
DIFF: https://github.com/llvm/llvm-project/commit/50746f28f12d7b28fdaa3fc0de5822ea42a0d5a4.diff

LOG: [flang] Don't do actual concatenation when computing LEN() of concatenated strings (#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.

Fixes #157763

Added: 
    flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90

Modified: 
    flang/lib/Lower/HlfirIntrinsics.cpp
    flang/test/Lower/HLFIR/assumed-rank-inquiries.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp
index 27c8bb87f7542..f63628d7824ff 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..59c597a60c515
--- /dev/null
+++ b/flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90
@@ -0,0 +1,54 @@
+! RUN: %flang_fc1 -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]]


        


More information about the flang-commits mailing list