On Tue, 6 Oct 2026, [email protected] wrote: > 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.
Ah, thanks for catching that. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? OK. Thanks, Richard. > 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) > -- Richard Biener <[email protected]> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)
