[flang-commits] [flang] [flang][Lower] Reassociate sums before kind conversion (PR #217283)
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 19 03:51:27 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Tom Eccles (tblah)
<details>
<summary>Changes</summary>
Handle one REAL or COMPLEX kind conversion around an eligible sum.
Leave the conversion around the rebuilt expression.
Keep conversions embedded in mixed-kind trees ineligible.
Tests cover enabled and disabled lowering for both numeric categories.
Assisted-by: Codex
---
<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
---
Full diff: https://github.com/llvm/llvm-project/pull/217283.diff
2 Files Affected:
- (modified) flang/lib/Evaluate/tools.cpp (+36-3)
- (modified) flang/test/Lower/split-sum-expression-tree-lowering.f90 (+79-20)
``````````diff
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 5eceb4562c4ba..4924da89a2318 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1397,6 +1397,16 @@ template <common::TypeCategory CAT, int KIND> struct SignedNumericExpr {
bool isPositive;
};
+struct HasConversionHelper : public AnyTraverse<HasConversionHelper> {
+ using Base = AnyTraverse<HasConversionHelper>;
+ HasConversionHelper() : Base{*this} {}
+ using Base::operator();
+ template <typename TO, common::TypeCategory FROM>
+ bool operator()(const Convert<TO, FROM> &) const {
+ return true;
+ }
+};
+
template <common::TypeCategory CAT, int KIND>
static void flattenTopLevelAddSubtract(const NumericExpr<CAT, KIND> &expr,
llvm::SmallVectorImpl<SignedNumericTerm<CAT, KIND>> &terms,
@@ -1464,8 +1474,29 @@ static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(const T &) {
}
template <common::TypeCategory CAT, int KIND>
-static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
+static std::optional<NumericExpr<CAT, KIND>> tryBuildSplitSumExpressionTree(
const NumericExpr<CAT, KIND> &expr) {
+ if (const auto *convert =
+ std::get_if<Convert<Numeric<CAT, KIND>, CAT>>(&expr.u)) {
+ std::optional<Expr<SomeKind<CAT>>> rewritten = common::visit(
+ [&](const auto &typedExpr) -> std::optional<Expr<SomeKind<CAT>>> {
+ if (auto result = tryBuildSplitSumExpressionTree(typedExpr))
+ return Expr<SomeKind<CAT>>{std::move(*result)};
+ return std::nullopt;
+ },
+ convert->left().u);
+ if (!rewritten)
+ return std::nullopt;
+ return NumericExpr<CAT, KIND>{
+ Convert<Numeric<CAT, KIND>, CAT>{std::move(*rewritten)}};
+ }
+
+ // Only a conversion around the complete expression is supported. Keep
+ // conversions embedded in a mixed-kind tree attached to their original
+ // operations until those cases have their own correctness coverage.
+ if (HasConversionHelper{}(expr))
+ return std::nullopt;
+
if (!std::get_if<Add<Numeric<CAT, KIND>>>(&expr.u) &&
!std::get_if<Subtract<Numeric<CAT, KIND>>>(&expr.u))
return std::nullopt;
@@ -1484,7 +1515,7 @@ static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
buildSignedAdd(std::move(tailExpr), std::move(headExpr));
assert(result.isPositive &&
"the first flattened term and therefore the split sum are positive");
- return Expr<SomeType>{std::move(result.expr)};
+ return std::move(result.expr);
}
template <common::TypeCategory CAT>
@@ -1496,7 +1527,9 @@ static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
CAT == common::TypeCategory::Complex) {
return common::visit(
[&](const auto &typedExpr) -> std::optional<Expr<SomeType>> {
- return tryBuildSplitSumExpressionTree(typedExpr);
+ if (auto result = tryBuildSplitSumExpressionTree(typedExpr))
+ return Expr<SomeType>{std::move(*result)};
+ return std::nullopt;
},
expr.u);
}
diff --git a/flang/test/Lower/split-sum-expression-tree-lowering.f90 b/flang/test/Lower/split-sum-expression-tree-lowering.f90
index 86899459a3aeb..186fa183cce07 100644
--- a/flang/test/Lower/split-sum-expression-tree-lowering.f90
+++ b/flang/test/Lower/split-sum-expression-tree-lowering.f90
@@ -813,33 +813,92 @@ subroutine guard_short_sum(x,a,b)
! NO-REWRITE: %[[RES:.*]] = arith.addf %[[XV]], %[[AB]]
! NO-REWRITE: hlfir.assign %[[RES]] to %[[X]]#0
-subroutine guard_mixed_kind(x,a,b,c,d,e,f)
+! The kind conversion remains around the reassociated expression.
+! Default: ((a*b + c*d) + e*f)
+! Rewritten: (e*f + (a*b + c*d))
+subroutine eligible_whole_real_kind_conversion(x,a,b,c,d,e,f)
real(8) :: x
real(4) :: a,b,c,d,e,f
x = a*b + c*d + e*f
end
-! NO-REWRITE-LABEL: func.func @_QPguard_mixed_kind
-! NO-REWRITE-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEa"}
-! NO-REWRITE-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEb"}
-! NO-REWRITE-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEc"}
-! NO-REWRITE-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEd"}
-! NO-REWRITE-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEe"}
-! NO-REWRITE-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEf"}
-! NO-REWRITE-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_mixed_kindEx"}
-! NO-REWRITE: %[[AV:.*]] = fir.load %[[A]]#0
-! NO-REWRITE: %[[BV:.*]] = fir.load %[[B]]#0
+! SPLIT-LABEL: func.func @_QPeligible_whole_real_kind_conversion
+! SPLIT: %[[EV:.*]] = fir.load
+! SPLIT: %[[FV:.*]] = fir.load
+! SPLIT: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
+! SPLIT: %[[AV:.*]] = fir.load
+! SPLIT: %[[BV:.*]] = fir.load
+! SPLIT: %[[AB:.*]] = arith.mulf %[[AV]], %[[BV]]
+! SPLIT: %[[CV:.*]] = fir.load
+! SPLIT: %[[DV:.*]] = fir.load
+! SPLIT: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
+! SPLIT: %[[HEAD:.*]] = arith.addf %[[AB]], %[[CD]]
+! SPLIT: %[[SUM:.*]] = arith.addf %[[EF]], %[[HEAD]]
+! SPLIT: %[[RES:.*]] = fir.convert %[[SUM]] : (f32) -> f64
+! SPLIT: hlfir.assign %[[RES]]
+
+! DEFAULT-LABEL: func.func @_QPeligible_whole_real_kind_conversion
+! DEFAULT: %[[AV:.*]] = fir.load
+! DEFAULT: %[[BV:.*]] = fir.load
+! DEFAULT: %[[AB:.*]] = arith.mulf %[[AV]], %[[BV]]
+! DEFAULT: %[[CV:.*]] = fir.load
+! DEFAULT: %[[DV:.*]] = fir.load
+! DEFAULT: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
+! DEFAULT: %[[HEAD:.*]] = arith.addf %[[AB]], %[[CD]]
+! DEFAULT: %[[EV:.*]] = fir.load
+! DEFAULT: %[[FV:.*]] = fir.load
+! DEFAULT: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
+! DEFAULT: %[[SUM:.*]] = arith.addf %[[HEAD]], %[[EF]]
+! DEFAULT: %[[RES:.*]] = fir.convert %[[SUM]] : (f32) -> f64
+! DEFAULT: hlfir.assign %[[RES]]
+
+! Default: ((a + b) + c)
+! Rewritten: (c + (a + b))
+subroutine eligible_whole_complex_kind_conversion(x,a,b,c)
+ complex(8) :: x
+ complex(4) :: a,b,c
+ x = a + b + c
+end
+
+! SPLIT-LABEL: func.func @_QPeligible_whole_complex_kind_conversion
+! SPLIT: %[[CV:.*]] = fir.load
+! SPLIT: %[[AV:.*]] = fir.load
+! SPLIT: %[[BV:.*]] = fir.load
+! SPLIT: %[[HEAD:.*]] = fir.addc %[[AV]], %[[BV]]
+! SPLIT: %[[SUM:.*]] = fir.addc %[[CV]], %[[HEAD]]
+! SPLIT: %[[RES:.*]] = fir.convert %[[SUM]] : (complex<f32>) -> complex<f64>
+! SPLIT: hlfir.assign %[[RES]]
+
+! DEFAULT-LABEL: func.func @_QPeligible_whole_complex_kind_conversion
+! DEFAULT: %[[AV:.*]] = fir.load
+! DEFAULT: %[[BV:.*]] = fir.load
+! DEFAULT: %[[HEAD:.*]] = fir.addc %[[AV]], %[[BV]]
+! DEFAULT: %[[CV:.*]] = fir.load
+! DEFAULT: %[[SUM:.*]] = fir.addc %[[HEAD]], %[[CV]]
+! DEFAULT: %[[RES:.*]] = fir.convert %[[SUM]] : (complex<f32>) -> complex<f64>
+! DEFAULT: hlfir.assign %[[RES]]
+
+! A conversion embedded in the additive tree is not yet eligible.
+subroutine guard_embedded_kind_conversion(x,a,b,c,d,e,f)
+ real(8) :: x,a,b,c,d
+ real(4) :: e,f
+ x = a*b + c*d + real(e*f,8)
+end
+
+! NO-REWRITE-LABEL: func.func @_QPguard_embedded_kind_conversion
+! NO-REWRITE: %[[AV:.*]] = fir.load
+! NO-REWRITE: %[[BV:.*]] = fir.load
! NO-REWRITE: %[[AB:.*]] = arith.mulf %[[AV]], %[[BV]]
-! NO-REWRITE: %[[CV:.*]] = fir.load %[[C]]#0
-! NO-REWRITE: %[[DV:.*]] = fir.load %[[D]]#0
+! NO-REWRITE: %[[CV:.*]] = fir.load
+! NO-REWRITE: %[[DV:.*]] = fir.load
! NO-REWRITE: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
-! NO-REWRITE: %[[ABCD:.*]] = arith.addf %[[AB]], %[[CD]]
-! NO-REWRITE: %[[EV:.*]] = fir.load %[[E]]#0
-! NO-REWRITE: %[[FV:.*]] = fir.load %[[F]]#0
-! NO-REWRITE: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
-! NO-REWRITE: %[[SUM:.*]] = arith.addf %[[ABCD]], %[[EF]]
-! NO-REWRITE: %[[RES:.*]] = fir.convert %[[SUM]]
-! NO-REWRITE: hlfir.assign %[[RES]] to %[[X]]#0
+! NO-REWRITE: %[[HEAD:.*]] = arith.addf %[[AB]], %[[CD]]
+! NO-REWRITE: %[[EV:.*]] = fir.load
+! NO-REWRITE: %[[FV:.*]] = fir.load
+! NO-REWRITE: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]] {{.*}} : f32
+! NO-REWRITE: %[[CONVERT:.*]] = fir.convert %[[EF]] : (f32) -> f64
+! NO-REWRITE: %[[SUM:.*]] = arith.addf %[[HEAD]], %[[CONVERT]]
+! NO-REWRITE: hlfir.assign %[[SUM]]
module split_sum_guard_mod
real(8), volatile :: use_volatile_x
``````````
</details>
https://github.com/llvm/llvm-project/pull/217283
More information about the flang-commits
mailing list