[flang-commits] [flang] [flang] Don't do actual concatenation when computing LEN() of concatenated strings (PR #180676)
via flang-commits
flang-commits at lists.llvm.org
Mon Feb 9 21:06:30 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Eugene Epshteyn (eugeneepshteyn)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/180676.diff
3 Files Affected:
- (modified) flang/lib/Lower/HlfirIntrinsics.cpp (+24)
- (modified) flang/test/Lower/HLFIR/assumed-rank-inquiries.f90 (+1-1)
- (added) flang/test/Lower/HLFIR/elemental-result-length-len-folding.f90 (+54)
``````````diff
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..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]]
``````````
</details>
https://github.com/llvm/llvm-project/pull/180676
More information about the flang-commits
mailing list