https://gcc.gnu.org/g:5f55b86f2737a046bb3d06cae52d1c96646b84fe
commit r17-4933-g5f55b86f2737a046bb3d06cae52d1c96646b84fe Author: Kyrylo Tkachov <[email protected]> Date: Mon Oct 5 22:46:52 2026 +0200 genmatch: Share transform copies for non-delayable for-iterators 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]> Diff: --- gcc/genmatch.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index 1a89b7c13c2f..da80a2c4778d 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; } @@ -2454,8 +2467,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)
