From: Kyrylo Tkachov <[email protected]>
When can_delay_subst is false, lower_for substitutes the for-iterator
into both the match and the result for each operator in the list. If
the result does not reference the iterator, replace_id still produces a
fresh deep copy, so every iteration holds a distinct result pointer even
though the result trees are structurally identical. The code generator
then emits the transform inline once per operator, bloating the output.
The existing sharing mechanism (compare_op, sinfo) already shares a
transform across operators when can_delay_subst is true, detecting
identical results by pointer equality. The same mechanism works for the
non-delayable case when the result pointer is not replaced.
Guard the replace_id call on the result with contains_id: skip the copy
when the iterator does not appear in the result. All iterations then
keep result_op pointing to the original s->result, compare_op returns
true for them, and the code generator outlines the transform once.
The main beneficiary is match.pd:3732 (combine_comparisons). Since
c7ebd58535a and bbc2517fe41 (2026-08-11), its outer (for bitop ...) list
mixes tcc_binary and tcc_comparison codes, blocking delayed substitution.
The result does not reference bitop, so without this fix every one of
the 1764 worklist entries gets its own result copy and its own
gimple_simplify_N function. This patch reduces the generated GIMPLE
matcher by about 1.2% and the GENERIC matcher by about 1.2%.
Also fix contains_id for c_expr: the previous code checked capture_ids,
which only tracks @N-style captures, so it always returned false for
for-iterator names. Replace it with a scan of the CPP_NAME tokens in
the inline C code, matching the lookup gen_transform performs at
code-generation time.
Bootstrapped and tested on aarch64-none-linux-gnu.
Ok for trunk?
Thanks,
Kyrill
gcc/ChangeLog:
* genmatch.cc (contains_id): For c_expr, check CPP_NAME tokens
rather than capture_ids to detect for-iterator references.
(lower_for): Skip result copy in replace_id when the for-iterator
does not appear in the result, to preserve pointer identity and
enable transform sharing.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/genmatch.cc | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc
index 1d53283e094..e6065a039ef 100644
--- a/gcc/genmatch.cc
+++ b/gcc/genmatch.cc
@@ -2273,7 +2273,20 @@ contains_id (operand *o, user_id *id)
|| (ife->falseexpr && contains_id (ife->falseexpr, id)));
if (c_expr *ce = dyn_cast<c_expr *> (o))
- return ce->capture_ids && ce->capture_ids->get (id->id);
+ {
+ /* Check whether any CPP_NAME token in the inline C code spells id->id.
+ gen_transform looks up CPP_NAME tokens in the id substitution table,
+ so the same check here determines whether the table needs an entry. */
+ for (unsigned i = 0; i < ce->code.length (); ++i)
+ {
+ const cpp_token *t = &ce->code[i];
+ if (t->type == CPP_NAME
+ && strcmp ((const char *) NODE_NAME (t->val.node.node),
+ id->id) == 0)
+ return true;
+ }
+ return false;
+ }
return false;
}
@@ -2460,8 +2473,8 @@ lower_for (simplify *sin, vec<simplify *>& simplifiers)
if (sin->kind == simplify::SIMPLIFY
|| !can_delay_subst)
match_op = replace_id (match_op, id, oper);
- if (result_op
- && !can_delay_subst)
+ if (result_op && !can_delay_subst
+ && contains_id (result_op, id))
result_op = replace_id (result_op, id, oper);
}
if (skip)
--
2.50.1 (Apple Git-155)