[flang-commits] [flang] [flang][Lower] Flatten signed real sum terms (PR #211829)
via flang-commits
flang-commits at lists.llvm.org
Fri Jul 24 08:27:37 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Tom Eccles (tblah)
<details>
<summary>Changes</summary>
Second part of generalisations requested in #<!-- -->207377.
Extend real sum reassociation to flatten unparenthesized addition and subtraction into signed terms. Rebuild split groups with addition and subtraction while preserving parenthesized subtrees as opaque values.
I did not observe any benchmark result changes as a result of this patch.
Assisted-by: Codex
---
Patch is 22.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/211829.diff
2 Files Affected:
- (modified) flang/lib/Evaluate/tools.cpp (+78-25)
- (modified) flang/test/Lower/split-sum-expression-tree-lowering.f90 (+224-27)
``````````diff
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 8742bb5000588..7b480255e2fec 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1360,33 +1360,79 @@ bool HasVolatileOrAsynchronousSymbol(const Expr<SomeType> &expr) {
return HasVolatileOrAsynchronousSymbolHelper{}(expr);
}
+namespace {
+
template <int KIND> using Real = Type<common::TypeCategory::Real, KIND>;
template <int KIND> using RealExpr = Expr<Real<KIND>>;
+template <int KIND> struct SignedRealTerm {
+ RealExpr<KIND> expr;
+ bool isPositive;
+};
+
+template <int KIND> struct SignedRealExpr {
+ RealExpr<KIND> expr;
+ bool isPositive;
+};
+
template <int KIND>
-static void flattenTopLevelAdds(
- const RealExpr<KIND> &expr, llvm::SmallVectorImpl<RealExpr<KIND>> &terms) {
- // Only flatten real Add nodes. Every other node, including Parentheses and
- // Subtract, is one opaque term whose internal expression tree is preserved.
+static void flattenTopLevelAddSubtract(const RealExpr<KIND> &expr,
+ llvm::SmallVectorImpl<SignedRealTerm<KIND>> &terms,
+ bool isPositive = true) {
+ // Only flatten real Add and Subtract nodes. Every other node, including
+ // Parentheses, is one opaque signed term whose tree is preserved.
if (const auto *add = std::get_if<Add<Real<KIND>>>(&expr.u)) {
- flattenTopLevelAdds(add->left(), terms);
- flattenTopLevelAdds(add->right(), terms);
+ flattenTopLevelAddSubtract(add->left(), terms, isPositive);
+ flattenTopLevelAddSubtract(add->right(), terms, isPositive);
+ return;
+ }
+ if (const auto *subtract = std::get_if<Subtract<Real<KIND>>>(&expr.u)) {
+ flattenTopLevelAddSubtract(subtract->left(), terms, isPositive);
+ flattenTopLevelAddSubtract(subtract->right(), terms, !isPositive);
return;
}
- terms.push_back(expr);
+ terms.push_back(SignedRealTerm<KIND>{expr, isPositive});
}
template <int KIND>
-static RealExpr<KIND> buildRightAssociatedAddFold(
- llvm::ArrayRef<RealExpr<KIND>> terms) {
- assert(!terms.empty() && "cannot build empty add fold");
- if (terms.size() == 1)
- return terms.front();
- RealExpr<KIND> result{terms.back()};
- for (const RealExpr<KIND> &term : llvm::reverse(terms.drop_back()))
- result = RealExpr<KIND>{Add<Real<KIND>>{term, result}};
- return result;
+static SignedRealExpr<KIND> buildRightAssociatedSignedFold(
+ llvm::MutableArrayRef<SignedRealTerm<KIND>> terms) {
+ assert(!terms.empty() && "cannot build empty signed fold");
+ const bool isPositive{terms.front().isPositive};
+ RealExpr<KIND> result{std::move(terms.back().expr)};
+ for (std::size_t i{terms.size() - 1}; i > 0; --i) {
+ SignedRealTerm<KIND> &term{terms[i - 1]};
+ const bool useAdd{term.isPositive == terms[i].isPositive};
+ if (useAdd)
+ result = RealExpr<KIND>{
+ Add<Real<KIND>>{std::move(term.expr), std::move(result)}};
+ else
+ result = RealExpr<KIND>{
+ Subtract<Real<KIND>>{std::move(term.expr), std::move(result)}};
+ }
+ return SignedRealExpr<KIND>{std::move(result), isPositive};
+}
+
+template <int KIND>
+static SignedRealExpr<KIND> buildSignedAdd(
+ SignedRealExpr<KIND> left, SignedRealExpr<KIND> right) {
+ if (left.isPositive == right.isPositive) {
+ return SignedRealExpr<KIND>{
+ RealExpr<KIND>{
+ Add<Real<KIND>>{std::move(left.expr), std::move(right.expr)}},
+ left.isPositive};
+ }
+ if (left.isPositive) {
+ return SignedRealExpr<KIND>{
+ RealExpr<KIND>{
+ Subtract<Real<KIND>>{std::move(left.expr), std::move(right.expr)}},
+ true};
+ }
+ // Prefer Y-X to introducing a unary negation for -X+Y.
+ return SignedRealExpr<KIND>{RealExpr<KIND>{Subtract<Real<KIND>>{
+ std::move(right.expr), std::move(left.expr)}},
+ true};
}
template <typename T>
@@ -1397,20 +1443,25 @@ static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(const T &) {
template <int KIND>
static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
const RealExpr<KIND> &expr) {
- if (!std::get_if<Add<Real<KIND>>>(&expr.u))
+ if (!std::get_if<Add<Real<KIND>>>(&expr.u) &&
+ !std::get_if<Subtract<Real<KIND>>>(&expr.u))
return std::nullopt;
- llvm::SmallVector<RealExpr<KIND>, 8> terms;
- flattenTopLevelAdds(expr, terms);
+ llvm::SmallVector<SignedRealTerm<KIND>, 8> terms;
+ flattenTopLevelAddSubtract(expr, terms);
if (terms.size() <= 2)
return std::nullopt;
- llvm::SmallVector<RealExpr<KIND>, 2> head{terms[0], terms[1]};
- llvm::SmallVector<RealExpr<KIND>, 8> tail(terms.begin() + 2, terms.end());
- RealExpr<KIND> headExpr = buildRightAssociatedAddFold<KIND>(head);
- RealExpr<KIND> tailExpr = buildRightAssociatedAddFold<KIND>(tail);
- return Expr<SomeType>{
- RealExpr<KIND>{Add<Real<KIND>>{std::move(tailExpr), headExpr}}};
+ llvm::MutableArrayRef<SignedRealTerm<KIND>> head{terms.data(), 2};
+ llvm::MutableArrayRef<SignedRealTerm<KIND>> tail{
+ terms.data() + 2, terms.size() - 2};
+ SignedRealExpr<KIND> headExpr = buildRightAssociatedSignedFold<KIND>(head);
+ SignedRealExpr<KIND> tailExpr = buildRightAssociatedSignedFold<KIND>(tail);
+ SignedRealExpr<KIND> result =
+ buildSignedAdd<KIND>(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)};
}
template <common::TypeCategory CAT>
@@ -1426,6 +1477,8 @@ static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
return std::nullopt;
}
+} // namespace
+
bool CanBuildSplitSumExpressionTree(
const Expr<SomeType> &lhs, const Expr<SomeType> &rhs) {
return rhs.Rank() == 0 && lhs.Rank() == 0 && !HasVectorSubscript(rhs) &&
diff --git a/flang/test/Lower/split-sum-expression-tree-lowering.f90 b/flang/test/Lower/split-sum-expression-tree-lowering.f90
index 9ba921b9f5a07..1b1400f756177 100644
--- a/flang/test/Lower/split-sum-expression-tree-lowering.f90
+++ b/flang/test/Lower/split-sum-expression-tree-lowering.f90
@@ -1,4 +1,4 @@
-! RUN: %flang_fc1 -emit-hlfir -freal-sum-reassociation -o - %s | FileCheck %s --check-prefixes=SPLIT,NO-REWRITE
+! RUN: %flang_fc1 -emit-hlfir -freal-sum-reassociation -o - %s | FileCheck %s --check-prefixes=SPLIT,NO-REWRITE --implicit-check-not=arith.negf
! RUN: %flang_fc1 -emit-hlfir -fno-real-sum-reassociation -o - %s | FileCheck %s --check-prefixes=DEFAULT,NO-REWRITE
! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s --check-prefixes=DEFAULT,NO-REWRITE
@@ -380,46 +380,46 @@ subroutine guard_whole_rhs_parentheses(x,a,b,c,d,e,f)
! NO-REWRITE: %[[PAREN:.*]] = hlfir.no_reassoc %[[SUM]]
! NO-REWRITE: hlfir.assign %[[PAREN]] to %[[X]]#0
-! Subtract is one opaque term below the Add spine. This does not flatten the
-! expression into signed terms.
+! The unparenthesized Subtract is flattened into separate positive and negative
+! terms instead of remaining an opaque head term.
! Default: (((x - a*b) + c*d) + e*f)
-! Rewritten: (e*f + ((x - a*b) + c*d))
-subroutine eligible_opaque_subtract(x,a,b,c,d,e,f)
+! Rewritten: (c*d + e*f) + (x - a*b)
+subroutine eligible_signed_subtract(x,a,b,c,d,e,f)
real(8) :: x,a,b,c,d,e,f
x = x - a*b + c*d + e*f
end
-! SPLIT-LABEL: func.func @_QPeligible_opaque_subtract
-! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEa"}
-! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEb"}
-! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEc"}
-! SPLIT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEd"}
-! SPLIT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEe"}
-! SPLIT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEf"}
-! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEx"}
+! SPLIT-LABEL: func.func @_QPeligible_signed_subtract
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEc"}
+! SPLIT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEd"}
+! SPLIT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEe"}
+! SPLIT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEf"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEx"}
+! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
+! SPLIT: %[[DV:.*]] = fir.load %[[D]]#0
+! SPLIT: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
! SPLIT: %[[EV:.*]] = fir.load %[[E]]#0
! SPLIT: %[[FV:.*]] = fir.load %[[F]]#0
! SPLIT: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
+! SPLIT: %[[TAIL:.*]] = arith.addf %[[CD]], %[[EF]]
! SPLIT: %[[XV:.*]] = fir.load %[[X]]#0
! SPLIT: %[[AV:.*]] = fir.load %[[A]]#0
! SPLIT: %[[BV:.*]] = fir.load %[[B]]#0
! SPLIT: %[[AB:.*]] = arith.mulf %[[AV]], %[[BV]]
-! SPLIT: %[[XAB:.*]] = arith.subf %[[XV]], %[[AB]]
-! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
-! SPLIT: %[[DV:.*]] = fir.load %[[D]]#0
-! SPLIT: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
-! SPLIT: %[[HEAD:.*]] = arith.addf %[[XAB]], %[[CD]]
-! SPLIT: %[[RES:.*]] = arith.addf %[[EF]], %[[HEAD]]
+! SPLIT: %[[HEAD:.*]] = arith.subf %[[XV]], %[[AB]]
+! SPLIT: %[[RES:.*]] = arith.addf %[[TAIL]], %[[HEAD]]
! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
-! DEFAULT-LABEL: func.func @_QPeligible_opaque_subtract
-! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEa"}
-! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEb"}
-! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEc"}
-! DEFAULT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEd"}
-! DEFAULT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEe"}
-! DEFAULT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEf"}
-! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_opaque_subtractEx"}
+! DEFAULT-LABEL: func.func @_QPeligible_signed_subtract
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEc"}
+! DEFAULT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEd"}
+! DEFAULT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEe"}
+! DEFAULT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEf"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_signed_subtractEx"}
! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
@@ -435,6 +435,203 @@ subroutine eligible_opaque_subtract(x,a,b,c,d,e,f)
! DEFAULT: %[[RES:.*]] = arith.addf %[[XABCD]], %[[EF]]
! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
+! The tail starts negative. Rebuild -b+c as -(b-c), then use the explicitly
+! permitted -X+Y -> Y-X reassociation to avoid a unary negation:
+! Default: (((x + a) - b) + c)
+! Rewritten: (x + a) - (b - c)
+subroutine eligible_leading_negative_tail(x,a,b,c)
+ real(8) :: x,a,b,c
+ x = x + a - b + c
+end
+
+! SPLIT-LABEL: func.func @_QPeligible_leading_negative_tail
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEc"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEx"}
+! SPLIT: %[[XV:.*]] = fir.load %[[X]]#0
+! SPLIT: %[[AV:.*]] = fir.load %[[A]]#0
+! SPLIT: %[[HEAD:.*]] = arith.addf %[[XV]], %[[AV]]
+! SPLIT: %[[BV:.*]] = fir.load %[[B]]#0
+! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
+! SPLIT: %[[TAIL:.*]] = arith.subf %[[BV]], %[[CV]]
+! SPLIT: %[[RES:.*]] = arith.subf %[[HEAD]], %[[TAIL]]
+! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! DEFAULT-LABEL: func.func @_QPeligible_leading_negative_tail
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEc"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_leading_negative_tailEx"}
+! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[XA:.*]] = arith.addf %[[XV]], %[[AV]]
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[XAB:.*]] = arith.subf %[[XA]], %[[BV]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[RES:.*]] = arith.addf %[[XAB]], %[[CV]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! The tail ends negative and can be rebuilt directly with Subtract.
+! Default: (((x + a) + b) - c)
+! Rewritten: (b - c) + (x + a)
+subroutine eligible_trailing_negative_tail(x,a,b,c)
+ real(8) :: x,a,b,c
+ x = x + a + b - c
+end
+
+! SPLIT-LABEL: func.func @_QPeligible_trailing_negative_tail
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEc"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEx"}
+! SPLIT: %[[BV:.*]] = fir.load %[[B]]#0
+! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
+! SPLIT: %[[TAIL:.*]] = arith.subf %[[BV]], %[[CV]]
+! SPLIT: %[[XV:.*]] = fir.load %[[X]]#0
+! SPLIT: %[[AV:.*]] = fir.load %[[A]]#0
+! SPLIT: %[[HEAD:.*]] = arith.addf %[[XV]], %[[AV]]
+! SPLIT: %[[RES:.*]] = arith.addf %[[TAIL]], %[[HEAD]]
+! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! DEFAULT-LABEL: func.func @_QPeligible_trailing_negative_tail
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEc"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_trailing_negative_tailEx"}
+! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[XA:.*]] = arith.addf %[[XV]], %[[AV]]
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[XAB:.*]] = arith.addf %[[XA]], %[[BV]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[RES:.*]] = arith.subf %[[XAB]], %[[CV]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! A root Subtract and consecutive negative terms are eligible. The entirely
+! negative tail is represented by its positive magnitude, without unary minus.
+! Default: (((x - a) - b) - c)
+! Rewritten: (x - a) - (b + c)
+subroutine eligible_consecutive_subtraction(x,a,b,c)
+ real(8) :: x,a,b,c
+ x = x - a - b - c
+end
+
+! SPLIT-LABEL: func.func @_QPeligible_consecutive_subtraction
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEc"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEx"}
+! SPLIT: %[[XV:.*]] = fir.load %[[X]]#0
+! SPLIT: %[[AV:.*]] = fir.load %[[A]]#0
+! SPLIT: %[[HEAD:.*]] = arith.subf %[[XV]], %[[AV]]
+! SPLIT: %[[BV:.*]] = fir.load %[[B]]#0
+! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
+! SPLIT: %[[TAIL:.*]] = arith.addf %[[BV]], %[[CV]]
+! SPLIT: %[[RES:.*]] = arith.subf %[[HEAD]], %[[TAIL]]
+! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! DEFAULT-LABEL: func.func @_QPeligible_consecutive_subtraction
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEc"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_consecutive_subtractionEx"}
+! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[XA:.*]] = arith.subf %[[XV]], %[[AV]]
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[XAB:.*]] = arith.subf %[[XA]], %[[BV]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[RES:.*]] = arith.subf %[[XAB]], %[[CV]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! Nested unparenthesized Add and Subtract nodes all contribute signed terms.
+! Default: ((((x - a) + b) - c) + d)
+! Rewritten: (b - (c - d)) + (x - a)
+subroutine eligible_nested_unparenthesized_subtraction(x,a,b,c,d)
+ real(8) :: x,a,b,c,d
+ x = x - a + b - c + d
+end
+
+! SPLIT-LABEL: func.func @_QPeligible_nested_unparenthesized_subtraction
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEc"}
+! SPLIT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEd"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEx"}
+! SPLIT: %[[BV:.*]] = fir.load %[[B]]#0
+! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
+! SPLIT: %[[DV:.*]] = fir.load %[[D]]#0
+! SPLIT: %[[CD:.*]] = arith.subf %[[CV]], %[[DV]]
+! SPLIT: %[[TAIL:.*]] = arith.subf %[[BV]], %[[CD]]
+! SPLIT: %[[XV:.*]] = fir.load %[[X]]#0
+! SPLIT: %[[AV:.*]] = fir.load %[[A]]#0
+! SPLIT: %[[HEAD:.*]] = arith.subf %[[XV]], %[[AV]]
+! SPLIT: %[[RES:.*]] = arith.addf %[[TAIL]], %[[HEAD]]
+! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! DEFAULT-LABEL: func.func @_QPeligible_nested_unparenthesized_subtraction
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEc"}
+! DEFAULT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEd"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_nested_unparenthesized_subtractionEx"}
+! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[XA:.*]] = arith.subf %[[XV]], %[[AV]]
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[XAB:.*]] = arith.addf %[[XA]], %[[BV]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[XABC:.*]] = arith.subf %[[XAB]], %[[CV]]
+! DEFAULT: %[[DV:.*]] = fir.load %[[D]]#0
+! DEFAULT: %[[RES:.*]] = arith.addf %[[XABC]], %[[DV]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! Subtraction immediately outside a parenthesized term changes the term's
+! outer sign, but the parenthesized b-c remains one opaque no_reassoc value.
+! Default: (((x + a) - (b-c)) + d)
+! Rewritten: (x + a) - ((b-c) - d)
+subroutine eligible_subtract_parenthesized_term(x,a,b,c,d)
+ real(8) :: x,a,b,c,d
+ x = x + a - (b-c) + d
+end
+
+! SPLIT-LABEL: func.func @_QPeligible_subtract_parenthesized_term
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFe...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/211829
More information about the flang-commits
mailing list