Author: Tom Eccles
Date: 2026-07-23T10:01:10+01:00
New Revision: 09ab7a31cff482b5b0ce40a940e01ee068a89117
URL: https://github.com/llvm/llvm-project/commit/09ab7a31cff482b5b0ce40a940e01ee068a89117
DIFF: https://github.com/llvm/llvm-project/commit/09ab7a31cff482b5b0ce40a940e01ee068a89117.diff
LOG: [flang][Lower] Admit opaque terms to real sum reassociation (#211316)
First part of generalisations requested in #207377.
The split-sum eligibility check rejected any RHS containing explicit
parentheses or subtraction, even though the Add flattener already
preserves every non-Add subtree as one opaque term.
Remove those blanket guards and their unused predicates. Document the
opaque-term invariant and extend the test to cover parenthesized
additions and subtractions, whole-RHS parentheses, and subtraction
terms.
I did not observe any benchmark result changes as a result of this
patch.
Assisted-by: Codex
Added:
Modified:
flang/include/flang/Evaluate/tools.h
flang/lib/Evaluate/tools.cpp
flang/test/Lower/split-sum-expression-tree-lowering.f90
Removed:
################################################################################
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 5a286e73dc39e..6d602da2a3e80 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1120,15 +1120,9 @@ bool HasConstant(const Expr<SomeType> &);
// Predicate: Does an expression contain a component
bool HasStructureComponent(const Expr<SomeType> &expr);
-// Predicate: does an expression contain parentheses?
-bool HasParentheses(const Expr<SomeType> &expr);
-
// Predicate: does an expression contain a procedure reference?
bool HasProcedureRef(const Expr<SomeType> &expr);
-// Predicate: does an expression contain subtraction?
-bool HasSubtract(const Expr<SomeType> &expr);
-
// Predicate: does an expression contain a VOLATILE or ASYNCHRONOUS symbol?
bool HasVolatileOrAsynchronousSymbol(const Expr<SomeType> &expr);
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 006fb0c4a49e1..8742bb5000588 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1327,15 +1327,6 @@ bool HasVectorSubscript(const ActualArgument &actual) {
namespace {
-struct HasParenthesesHelper : public AnyTraverse<HasParenthesesHelper> {
- using Base = AnyTraverse<HasParenthesesHelper>;
- HasParenthesesHelper() : Base{*this} {}
- using Base::operator();
- template <typename T> bool operator()(const Parentheses<T> &) const {
- return true;
- }
-};
-
struct HasProcedureRefHelper : public AnyTraverse<HasProcedureRefHelper> {
using Base = AnyTraverse<HasProcedureRefHelper>;
HasProcedureRefHelper() : Base{*this} {}
@@ -1343,15 +1334,6 @@ struct HasProcedureRefHelper : public AnyTraverse<HasProcedureRefHelper> {
bool operator()(const ProcedureRef &) const { return true; }
};
-struct HasSubtractHelper : public AnyTraverse<HasSubtractHelper> {
- using Base = AnyTraverse<HasSubtractHelper>;
- HasSubtractHelper() : Base{*this} {}
- using Base::operator();
- template <typename T> bool operator()(const Subtract<T> &) const {
- return true;
- }
-};
-
struct HasVolatileOrAsynchronousSymbolHelper
: public AnyTraverse<HasVolatileOrAsynchronousSymbolHelper> {
using Base = AnyTraverse<HasVolatileOrAsynchronousSymbolHelper>;
@@ -1370,18 +1352,10 @@ struct HasVolatileOrAsynchronousSymbolHelper
} // namespace
-bool HasParentheses(const Expr<SomeType> &expr) {
- return HasParenthesesHelper{}(expr);
-}
-
bool HasProcedureRef(const Expr<SomeType> &expr) {
return HasProcedureRefHelper{}(expr);
}
-bool HasSubtract(const Expr<SomeType> &expr) {
- return HasSubtractHelper{}(expr);
-}
-
bool HasVolatileOrAsynchronousSymbol(const Expr<SomeType> &expr) {
return HasVolatileOrAsynchronousSymbolHelper{}(expr);
}
@@ -1393,6 +1367,8 @@ template <int KIND> using RealExpr = Expr<Real<KIND>>;
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.
if (const auto *add = std::get_if<Add<Real<KIND>>>(&expr.u)) {
flattenTopLevelAdds(add->left(), terms);
flattenTopLevelAdds(add->right(), terms);
@@ -1452,13 +1428,9 @@ static std::optional<Expr<SomeType>> tryBuildSplitSumExpressionTree(
bool CanBuildSplitSumExpressionTree(
const Expr<SomeType> &lhs, const Expr<SomeType> &rhs) {
- // The split only understands top-level Add nodes. Reject Subtract
- // conservatively for now rather than trying to model signed terms in
- // additive chains; this also rejects subtraction in subexpressions.
return rhs.Rank() == 0 && lhs.Rank() == 0 && !HasVectorSubscript(rhs) &&
- !HasVectorSubscript(lhs) && !HasParentheses(rhs) && !HasSubtract(rhs) &&
- !HasProcedureRef(rhs) && !HasProcedureRef(lhs) &&
- !HasVolatileOrAsynchronousSymbol(rhs) &&
+ !HasVectorSubscript(lhs) && !HasProcedureRef(rhs) &&
+ !HasProcedureRef(lhs) && !HasVolatileOrAsynchronousSymbol(rhs) &&
!HasVolatileOrAsynchronousSymbol(lhs);
}
diff --git a/flang/test/Lower/split-sum-expression-tree-lowering.f90 b/flang/test/Lower/split-sum-expression-tree-lowering.f90
index dc89793f7832d..9ba921b9f5a07 100644
--- a/flang/test/Lower/split-sum-expression-tree-lowering.f90
+++ b/flang/test/Lower/split-sum-expression-tree-lowering.f90
@@ -232,36 +232,143 @@ subroutine eligible_scalar_term(x,a,b,c,d,e)
! DEFAULT: %[[RES:.*]] = arith.addf %[[XABC]], %[[DE]]
! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
-subroutine guard_parentheses(x,a,b,c,d,e,f)
+! Default: (((x + (a-b)) + (c-d)) + (e-f))
+! Rewritten: ((c-d) + (e-f)) + (x + (a-b))
+subroutine eligible_parenthesized_subtractions(x,a,b,c,d,e,f)
real(8) :: x,a,b,c,d,e,f
- x = (x + a*b) + c*d + e*f
+ x = x + (a-b) + (c-d) + (e-f)
end
-! NO-REWRITE-LABEL: func.func @_QPguard_parentheses
-! NO-REWRITE-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_parenthesesEx"}
-! NO-REWRITE-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_parenthesesEe"}
-! NO-REWRITE: fir.load %[[X]]#0
-! NO-REWRITE: hlfir.no_reassoc
-! NO-REWRITE: fir.load %[[E]]#0
+! SPLIT-LABEL: func.func @_QPeligible_parenthesized_subtractions
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEc"}
+! SPLIT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEd"}
+! SPLIT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEe"}
+! SPLIT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEf"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEx"}
+! SPLIT: %[[CV:.*]] = fir.load %[[C]]#0
+! SPLIT: %[[DV:.*]] = fir.load %[[D]]#0
+! SPLIT: %[[CD_SUB:.*]] = arith.subf %[[CV]], %[[DV]]
+! SPLIT: %[[CD:.*]] = hlfir.no_reassoc %[[CD_SUB]]
+! SPLIT: %[[EV:.*]] = fir.load %[[E]]#0
+! SPLIT: %[[FV:.*]] = fir.load %[[F]]#0
+! SPLIT: %[[EF_SUB:.*]] = arith.subf %[[EV]], %[[FV]]
+! SPLIT: %[[EF:.*]] = hlfir.no_reassoc %[[EF_SUB]]
+! 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_SUB:.*]] = arith.subf %[[AV]], %[[BV]]
+! SPLIT: %[[AB:.*]] = hlfir.no_reassoc %[[AB_SUB]]
+! SPLIT: %[[HEAD:.*]] = arith.addf %[[XV]], %[[AB]]
+! SPLIT: %[[RES:.*]] = arith.addf %[[TAIL]], %[[HEAD]]
+! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! DEFAULT-LABEL: func.func @_QPeligible_parenthesized_subtractions
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEc"}
+! DEFAULT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEd"}
+! DEFAULT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEe"}
+! DEFAULT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEf"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_subtractionsEx"}
+! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[AB_SUB:.*]] = arith.subf %[[AV]], %[[BV]]
+! DEFAULT: %[[AB:.*]] = hlfir.no_reassoc %[[AB_SUB]]
+! DEFAULT: %[[XAB:.*]] = arith.addf %[[XV]], %[[AB]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[DV:.*]] = fir.load %[[D]]#0
+! DEFAULT: %[[CD_SUB:.*]] = arith.subf %[[CV]], %[[DV]]
+! DEFAULT: %[[CD:.*]] = hlfir.no_reassoc %[[CD_SUB]]
+! DEFAULT: %[[XABCD:.*]] = arith.addf %[[XAB]], %[[CD]]
+! DEFAULT: %[[EV:.*]] = fir.load %[[E]]#0
+! DEFAULT: %[[FV:.*]] = fir.load %[[F]]#0
+! DEFAULT: %[[EF_SUB:.*]] = arith.subf %[[EV]], %[[FV]]
+! DEFAULT: %[[EF:.*]] = hlfir.no_reassoc %[[EF_SUB]]
+! DEFAULT: %[[RES:.*]] = arith.addf %[[XABCD]], %[[EF]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
-subroutine guard_subtract(x,a,b,c,d,e,f)
+! The parenthesized addition is moved as one opaque term; its inner Add is not
+! part of the top-level additive spine.
+! Default: (((x + (a+b)) + c*d) + e*f)
+! Rewritten: ((c*d + e*f) + (x + (a+b)))
+subroutine eligible_parenthesized_add(x,a,b,c,d,e,f)
real(8) :: x,a,b,c,d,e,f
- x = x - a*b + c*d + e*f
+ x = x + (a+b) + c*d + e*f
end
-! NO-REWRITE-LABEL: func.func @_QPguard_subtract
-! NO-REWRITE-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEa"}
-! NO-REWRITE-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEb"}
-! NO-REWRITE-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEc"}
-! NO-REWRITE-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEd"}
-! NO-REWRITE-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEe"}
-! NO-REWRITE-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEf"}
-! NO-REWRITE-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_subtractEx"}
+! SPLIT-LABEL: func.func @_QPeligible_parenthesized_add
+! SPLIT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEa"}
+! SPLIT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEb"}
+! SPLIT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEc"}
+! SPLIT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEd"}
+! SPLIT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEe"}
+! SPLIT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEf"}
+! SPLIT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEx"}
+! 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_ADD:.*]] = arith.addf %[[AV]], %[[BV]]
+! SPLIT: %[[AB:.*]] = hlfir.no_reassoc %[[AB_ADD]]
+! SPLIT: %[[HEAD:.*]] = arith.addf %[[XV]], %[[AB]]
+! SPLIT: %[[RES:.*]] = arith.addf %[[TAIL]], %[[HEAD]]
+! SPLIT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! DEFAULT-LABEL: func.func @_QPeligible_parenthesized_add
+! DEFAULT-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEa"}
+! DEFAULT-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEb"}
+! DEFAULT-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEc"}
+! DEFAULT-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEd"}
+! DEFAULT-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEe"}
+! DEFAULT-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEf"}
+! DEFAULT-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFeligible_parenthesized_addEx"}
+! DEFAULT: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[AB_ADD:.*]] = arith.addf %[[AV]], %[[BV]]
+! DEFAULT: %[[AB:.*]] = hlfir.no_reassoc %[[AB_ADD]]
+! DEFAULT: %[[XAB:.*]] = arith.addf %[[XV]], %[[AB]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[DV:.*]] = fir.load %[[D]]#0
+! DEFAULT: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
+! DEFAULT: %[[XABCD:.*]] = arith.addf %[[XAB]], %[[CD]]
+! DEFAULT: %[[EV:.*]] = fir.load %[[E]]#0
+! DEFAULT: %[[FV:.*]] = fir.load %[[F]]#0
+! DEFAULT: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
+! DEFAULT: %[[RES:.*]] = arith.addf %[[XABCD]], %[[EF]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
+
+! A Parentheses root is not a top-level Add and therefore is not rewritten.
+! Default: ((((x + a*b) + c*d) + e*f))
+! Rewritten: ((((x + a*b) + c*d) + e*f))
+subroutine guard_whole_rhs_parentheses(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
+
+! NO-REWRITE-LABEL: func.func @_QPguard_whole_rhs_parentheses
+! NO-REWRITE-DAG: %[[A:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEa"}
+! NO-REWRITE-DAG: %[[B:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEb"}
+! NO-REWRITE-DAG: %[[C:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEc"}
+! NO-REWRITE-DAG: %[[D:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEd"}
+! NO-REWRITE-DAG: %[[E:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEe"}
+! NO-REWRITE-DAG: %[[F:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEf"}
+! NO-REWRITE-DAG: %[[X:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFguard_whole_rhs_parenthesesEx"}
! NO-REWRITE: %[[XV:.*]] = fir.load %[[X]]#0
! NO-REWRITE: %[[AV:.*]] = fir.load %[[A]]#0
! NO-REWRITE: %[[BV:.*]] = fir.load %[[B]]#0
! NO-REWRITE: %[[AB:.*]] = arith.mulf %[[AV]], %[[BV]]
-! NO-REWRITE: %[[XAB:.*]] = arith.subf %[[XV]], %[[AB]]
+! NO-REWRITE: %[[XAB:.*]] = arith.addf %[[XV]], %[[AB]]
! NO-REWRITE: %[[CV:.*]] = fir.load %[[C]]#0
! NO-REWRITE: %[[DV:.*]] = fir.load %[[D]]#0
! NO-REWRITE: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
@@ -269,8 +376,64 @@ subroutine guard_subtract(x,a,b,c,d,e,f)
! NO-REWRITE: %[[EV:.*]] = fir.load %[[E]]#0
! NO-REWRITE: %[[FV:.*]] = fir.load %[[F]]#0
! NO-REWRITE: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
-! NO-REWRITE: %[[RES:.*]] = arith.addf %[[XABCD]], %[[EF]]
-! NO-REWRITE: hlfir.assign %[[RES]] to %[[X]]#0
+! NO-REWRITE: %[[SUM:.*]] = arith.addf %[[XABCD]], %[[EF]]
+! 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.
+! 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)
+ 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: %[[EV:.*]] = fir.load %[[E]]#0
+! SPLIT: %[[FV:.*]] = fir.load %[[F]]#0
+! SPLIT: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
+! 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: 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: %[[XV:.*]] = fir.load %[[X]]#0
+! DEFAULT: %[[AV:.*]] = fir.load %[[A]]#0
+! DEFAULT: %[[BV:.*]] = fir.load %[[B]]#0
+! DEFAULT: %[[AB:.*]] = arith.mulf %[[AV]], %[[BV]]
+! DEFAULT: %[[XAB:.*]] = arith.subf %[[XV]], %[[AB]]
+! DEFAULT: %[[CV:.*]] = fir.load %[[C]]#0
+! DEFAULT: %[[DV:.*]] = fir.load %[[D]]#0
+! DEFAULT: %[[CD:.*]] = arith.mulf %[[CV]], %[[DV]]
+! DEFAULT: %[[XABCD:.*]] = arith.addf %[[XAB]], %[[CD]]
+! DEFAULT: %[[EV:.*]] = fir.load %[[E]]#0
+! DEFAULT: %[[FV:.*]] = fir.load %[[F]]#0
+! DEFAULT: %[[EF:.*]] = arith.mulf %[[EV]], %[[FV]]
+! DEFAULT: %[[RES:.*]] = arith.addf %[[XABCD]], %[[EF]]
+! DEFAULT: hlfir.assign %[[RES]] to %[[X]]#0
real(8) function foo(a)
real(8) :: a