On Thu, 16 Jul 2026, Tamar Christina wrote:
> This extends folding to take an optional gimplifier (not a fan of the name
> but it's what it was called before) to use during folding.
>
> This allows you to specify which .pd file should be used during the fold.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu,
> arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
> -m32, -m64 and no issues.
>
> Ok for master?
See 3/3. This also raises the question (again) how separate namespace
simplifiers integrate with the "main" simplifiers. As implemented
in 1/3 they do not know each others (but at least constant folding
is done via the resimplify wrapper). Does this mean we could end
up needing to iterate folding with both? Doesn't matter much
for ISEL instruction selection (but IIRC your ISEL patterns are
not that but "simplifiers"), but eventually for your idea of
doing target specific folding?
Wouldn't that ask for a single matcher but patterns gated on
enabled flags?
Thanks,
Richard.
>
> Thanks,
> Tamar
>
> gcc/ChangeLog:
>
> * gimple-fold.cc (fold_stmt_1): Pass gimplifier along.
> (fold_stmt): New.
> (fold_stmt_inplace): Pass gimplifier along.
> (and_comparisons_1, and_var_with_comparison, and_var_with_comparison_1,
> or_comparisons_1, or_var_with_comparison, or_var_with_comparison_1,
> (maybe_fold_comparisons_from_match_pd): Likewise.
> (maybe_fold_or_comparisons): Likewise.
> (maybe_fold_and_comparisons): New.
> (gimple_fold_stmt_to_constant_1): New.
> * gimple-fold.h (fold_stmt_inplace, fold_stmt): New.
> (maybe_fold_and_comparisons, gimple_fold_stmt_to_constant_1): New.
>
> ---
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index
> d1da1f00f0fed7765c8785158a915cb9bb3c88c0..b642cd25c773b29076e0711b215d0b32d11ceef9
> 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -6774,7 +6774,7 @@ maybe_canonicalize_mem_ref_addr (tree *t, bool is_debug
> = false)
>
> static bool
> fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize)
> (tree),
> - bitmap dce_worklist = nullptr)
> + gimple_match_simplify_fn simplifier, bitmap dce_worklist = nullptr)
> {
> bool changed = false;
> gimple *stmt = gsi_stmt (*gsi);
> @@ -6937,7 +6937,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace,
> tree (*valueize) (tree),
> {
> gimple_seq seq = NULL;
> gimple_match_op res_op;
> - res_op.set_simplifier (gimple_simplify);
> + res_op.set_simplifier (simplifier);
> if (gimple_simplify (stmt, &res_op, inplace ? NULL : &seq,
> valueize, valueize)
> && replace_stmt_with_simplification (gsi, &res_op, &seq, inplace,
> @@ -7094,13 +7094,28 @@ follow_all_ssa_edges (tree val)
> bool
> fold_stmt (gimple_stmt_iterator *gsi, bitmap dce_bitmap)
> {
> - return fold_stmt_1 (gsi, false, no_follow_ssa_edges, dce_bitmap);
> + return fold_stmt (gsi, gimple_simplify,dce_bitmap);
> }
>
> bool
> fold_stmt (gimple_stmt_iterator *gsi, tree (*valueize) (tree), bitmap
> dce_bitmap)
> {
> - return fold_stmt_1 (gsi, false, valueize, dce_bitmap);
> + return fold_stmt (gsi, valueize, gimple_simplify, dce_bitmap);
> +}
> +
> +bool
> +fold_stmt (gimple_stmt_iterator *gsi, gimple_match_simplify_fn simplifier,
> + bitmap dce_bitmap)
> +{
> + return fold_stmt_1 (gsi, false, no_follow_ssa_edges, simplifier,
> + dce_bitmap);
> +}
> +
> +bool
> +fold_stmt (gimple_stmt_iterator *gsi, tree (*valueize) (tree),
> + gimple_match_simplify_fn simplifier, bitmap dce_bitmap)
> +{
> + return fold_stmt_1 (gsi, false, valueize, simplifier, dce_bitmap);
> }
>
> /* Perform the minimal folding on statement *GSI. Only operations like
> @@ -7112,10 +7127,11 @@ fold_stmt (gimple_stmt_iterator *gsi, tree
> (*valueize) (tree), bitmap dce_bitmap
> which can produce *&x = 0. */
>
> bool
> -fold_stmt_inplace (gimple_stmt_iterator *gsi, tree (*valueize) (tree))
> +fold_stmt_inplace (gimple_stmt_iterator *gsi, tree (*valueize) (tree),
> + gimple_match_simplify_fn simplifier)
> {
> gimple *stmt = gsi_stmt (*gsi);
> - bool changed = fold_stmt_1 (gsi, true, valueize);
> + bool changed = fold_stmt_1 (gsi, true, valueize, simplifier);
> gcc_assert (gsi_stmt (*gsi) == stmt);
> return changed;
> }
> @@ -7257,27 +7273,28 @@ same_bool_result_p (const_tree op1, const_tree op2)
>
> static tree
> and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
> - enum tree_code code2, tree op2a, tree op2b, basic_block);
> + enum tree_code code2, tree op2a, tree op2b, basic_block,
> + gimple_match_simplify_fn);
> static tree
> and_var_with_comparison (tree type, tree var, bool invert,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block);
> + basic_block, gimple_match_simplify_fn);
> static tree
> and_var_with_comparison_1 (tree type, gimple *stmt,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block);
> + basic_block, gimple_match_simplify_fn);
> static tree
> or_comparisons_1 (tree, enum tree_code code1, tree op1a, tree op1b,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block);
> + basic_block, gimple_match_simplify_fn);
> static tree
> or_var_with_comparison (tree, tree var, bool invert,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block);
> + basic_block, gimple_match_simplify_fn);
> static tree
> or_var_with_comparison_1 (tree, gimple *stmt,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block);
> + basic_block, gimple_match_simplify_fn);
>
> /* Helper function for and_comparisons_1: try to simplify the AND of the
> ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B).
> @@ -7287,7 +7304,8 @@ or_var_with_comparison_1 (tree, gimple *stmt,
> static tree
> and_var_with_comparison (tree type, tree var, bool invert,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> tree t;
> gimple *stmt = SSA_NAME_DEF_STMT (var);
> @@ -7302,10 +7320,10 @@ and_var_with_comparison (tree type, tree var, bool
> invert,
> if (invert)
> t = or_var_with_comparison_1 (type, stmt,
> invert_tree_comparison (code2, false),
> - op2a, op2b, outer_cond_bb);
> + op2a, op2b, outer_cond_bb, simplifier);
> else
> t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b,
> - outer_cond_bb);
> + outer_cond_bb, simplifier);
> return canonicalize_bool (t, invert);
> }
>
> @@ -7316,7 +7334,8 @@ and_var_with_comparison (tree type, tree var, bool
> invert,
> static tree
> and_var_with_comparison_1 (tree type, gimple *stmt,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> tree var = gimple_assign_lhs (stmt);
> tree true_test_var = NULL_TREE;
> @@ -7351,7 +7370,7 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
> gimple_assign_rhs2 (stmt),
> code2,
> op2a,
> - op2b, outer_cond_bb);
> + op2b, outer_cond_bb, simplifier);
> if (t)
> return t;
> }
> @@ -7383,12 +7402,12 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
> return (is_and
> ? boolean_false_node
> : and_var_with_comparison (type, inner2, false, code2, op2a,
> - op2b, outer_cond_bb));
> + op2b, outer_cond_bb, simplifier));
> else if (inner2 == false_test_var)
> return (is_and
> ? boolean_false_node
> : and_var_with_comparison (type, inner1, false, code2, op2a,
> - op2b, outer_cond_bb));
> + op2b, outer_cond_bb, simplifier));
>
> /* Next, redistribute/reassociate the AND across the inner tests.
> Compute the first partial result, (inner1 AND (op2a code op2b)) */
> @@ -7399,7 +7418,8 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
> gimple_assign_rhs1 (s),
> gimple_assign_rhs2 (s),
> code2, op2a, op2b,
> - outer_cond_bb)))
> + outer_cond_bb,
> + simplifier)))
> {
> /* Handle the AND case, where we are reassociating:
> (inner1 AND inner2) AND (op2a code2 op2b)
> @@ -7432,7 +7452,8 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
> gimple_assign_rhs1 (s),
> gimple_assign_rhs2 (s),
> code2, op2a, op2b,
> - outer_cond_bb)))
> + outer_cond_bb,
> + simplifier)))
> {
> /* Handle the AND case, where we are reassociating:
> (inner1 AND inner2) AND (op2a code2 op2b)
> @@ -7487,7 +7508,8 @@ and_var_with_comparison_1 (tree type, gimple *stmt,
> static tree
> and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> tree truth_type = truth_type_for (TREE_TYPE (op1a));
>
> @@ -7531,7 +7553,7 @@ and_comparisons_1 (tree type, enum tree_code code1,
> tree op1a, tree op1b,
> case GIMPLE_ASSIGN:
> /* Try to simplify by copy-propagating the definition. */
> return and_var_with_comparison (type, op1a, invert, code2, op2a,
> - op2b, outer_cond_bb);
> + op2b, outer_cond_bb, simplifier);
>
> case GIMPLE_PHI:
> /* If every argument to the PHI produces the same result when
> @@ -7583,7 +7605,8 @@ and_comparisons_1 (tree type, enum tree_code code1,
> tree op1a, tree op1b,
> return NULL_TREE;
> temp = and_var_with_comparison (type, arg, invert, code2,
> op2a, op2b,
> - outer_cond_bb);
> + outer_cond_bb,
> + simplifier);
> if (!temp)
> return NULL_TREE;
> else if (!result)
> @@ -7648,7 +7671,8 @@ maybe_fold_comparisons_from_match_pd (tree type, enum
> tree_code code,
> tree op1a, tree op1b,
> enum tree_code code2, tree op2a,
> tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> /* Allocate gimple stmt1 on the stack. */
> gassign *stmt1
> @@ -7690,6 +7714,7 @@ maybe_fold_comparisons_from_match_pd (tree type, enum
> tree_code code,
> gimple_match_op op (gimple_match_cond::UNCOND, code,
> type, gimple_assign_lhs (stmt1),
> gimple_assign_lhs (stmt2));
> + op.set_simplifier (simplifier);
> fosa_bb = outer_cond_bb;
> auto_vec<std::pair<tree, flow_sensitive_info_storage>, 8> unwind_stack;
> fosa_unwind = &unwind_stack;
> @@ -9203,19 +9228,21 @@ tree
> maybe_fold_and_comparisons (tree type,
> enum tree_code code1, tree op1a, tree op1b,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b,
> - outer_cond_bb))
> + outer_cond_bb, simplifier))
> return t;
>
> if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b,
> - outer_cond_bb))
> + outer_cond_bb, simplifier))
> return t;
>
> if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR,
> code1,
> op1a, op1b, code2, op2a,
> - op2b, outer_cond_bb))
> + op2b, outer_cond_bb,
> + simplifier))
> return t;
>
> return NULL_TREE;
> @@ -9229,7 +9256,8 @@ maybe_fold_and_comparisons (tree type,
> static tree
> or_var_with_comparison (tree type, tree var, bool invert,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> tree t;
> gimple *stmt = SSA_NAME_DEF_STMT (var);
> @@ -9244,10 +9272,10 @@ or_var_with_comparison (tree type, tree var, bool
> invert,
> if (invert)
> t = and_var_with_comparison_1 (type, stmt,
> invert_tree_comparison (code2, false),
> - op2a, op2b, outer_cond_bb);
> + op2a, op2b, outer_cond_bb, simplifier);
> else
> t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b,
> - outer_cond_bb);
> + outer_cond_bb, simplifier);
> return canonicalize_bool (t, invert);
> }
>
> @@ -9258,7 +9286,8 @@ or_var_with_comparison (tree type, tree var, bool
> invert,
> static tree
> or_var_with_comparison_1 (tree type, gimple *stmt,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> tree var = gimple_assign_lhs (stmt);
> tree true_test_var = NULL_TREE;
> @@ -9291,7 +9320,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
> tree t = or_comparisons_1 (type, innercode,
> gimple_assign_rhs1 (stmt),
> gimple_assign_rhs2 (stmt),
> - code2, op2a, op2b, outer_cond_bb);
> + code2, op2a, op2b, outer_cond_bb,
> + simplifier);
> if (t)
> return t;
> }
> @@ -9323,12 +9353,12 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
> return (is_or
> ? boolean_true_node
> : or_var_with_comparison (type, inner2, false, code2, op2a,
> - op2b, outer_cond_bb));
> + op2b, outer_cond_bb, simplifier));
> else if (inner2 == false_test_var)
> return (is_or
> ? boolean_true_node
> : or_var_with_comparison (type, inner1, false, code2, op2a,
> - op2b, outer_cond_bb));
> + op2b, outer_cond_bb, simplifier));
>
> /* Next, redistribute/reassociate the OR across the inner tests.
> Compute the first partial result, (inner1 OR (op2a code op2b)) */
> @@ -9339,7 +9369,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
> gimple_assign_rhs1 (s),
> gimple_assign_rhs2 (s),
> code2, op2a, op2b,
> - outer_cond_bb)))
> + outer_cond_bb,
> + simplifier)))
> {
> /* Handle the OR case, where we are reassociating:
> (inner1 OR inner2) OR (op2a code2 op2b)
> @@ -9372,7 +9403,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
> gimple_assign_rhs1 (s),
> gimple_assign_rhs2 (s),
> code2, op2a, op2b,
> - outer_cond_bb)))
> + outer_cond_bb,
> + simplifier)))
> {
> /* Handle the OR case, where we are reassociating:
> (inner1 OR inner2) OR (op2a code2 op2b)
> @@ -9428,7 +9460,8 @@ or_var_with_comparison_1 (tree type, gimple *stmt,
> static tree
> or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> tree truth_type = truth_type_for (TREE_TYPE (op1a));
>
> @@ -9472,7 +9505,7 @@ or_comparisons_1 (tree type, enum tree_code code1, tree
> op1a, tree op1b,
> case GIMPLE_ASSIGN:
> /* Try to simplify by copy-propagating the definition. */
> return or_var_with_comparison (type, op1a, invert, code2, op2a,
> - op2b, outer_cond_bb);
> + op2b, outer_cond_bb, simplifier);
>
> case GIMPLE_PHI:
> /* If every argument to the PHI produces the same result when
> @@ -9523,7 +9556,8 @@ or_comparisons_1 (tree type, enum tree_code code1, tree
> op1a, tree op1b,
> gimple_bb (stmt)))
> return NULL_TREE;
> temp = or_var_with_comparison (type, arg, invert, code2,
> - op2a, op2b, outer_cond_bb);
> + op2a, op2b, outer_cond_bb,
> + simplifier);
> if (!temp)
> return NULL_TREE;
> else if (!result)
> @@ -9555,19 +9589,21 @@ tree
> maybe_fold_or_comparisons (tree type,
> enum tree_code code1, tree op1a, tree op1b,
> enum tree_code code2, tree op2a, tree op2b,
> - basic_block outer_cond_bb)
> + basic_block outer_cond_bb,
> + gimple_match_simplify_fn simplifier)
> {
> if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b,
> - outer_cond_bb))
> + outer_cond_bb, simplifier))
> return t;
>
> if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b,
> - outer_cond_bb))
> + outer_cond_bb, simplifier))
> return t;
>
> if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR,
> code1,
> op1a, op1b, code2, op2a,
> - op2b, outer_cond_bb))
> + op2b, outer_cond_bb,
> + simplifier))
> return t;
>
> return NULL_TREE;
> @@ -9584,10 +9620,11 @@ maybe_fold_or_comparisons (tree type,
>
> tree
> gimple_fold_stmt_to_constant_1 (gimple *stmt, tree (*valueize) (tree),
> - tree (*gvalueize) (tree))
> + tree (*gvalueize) (tree),
> + gimple_match_simplify_fn simplifier)
> {
> gimple_match_op res_op;
> - res_op.set_simplifier (gimple_simplify);
> + res_op.set_simplifier (simplifier);
> /* ??? The SSA propagators do not correctly deal with following SSA
> use-def
> edges if there are intermediate VARYING defs. For this reason
> do not follow SSA edges here even though SCCVN can technically
> diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
> index
> ca7519c4c8904127ad5a80e1d39101550b397d91..211f8901461fe6dc20864cd9ba8c9277ff19dc99
> 100644
> --- a/gcc/gimple-fold.h
> +++ b/gcc/gimple-fold.h
> @@ -36,17 +36,27 @@ extern tree follow_single_use_edges (tree);
> extern tree follow_all_ssa_edges (tree);
> extern bool fold_stmt (gimple_stmt_iterator *, bitmap = nullptr);
> extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree), bitmap =
> nullptr);
> -extern bool fold_stmt_inplace (gimple_stmt_iterator *, tree (*) (tree) =
> no_follow_ssa_edges);
> +extern bool fold_stmt (gimple_stmt_iterator *,
> + gimple_match_simplify_fn, bitmap = nullptr);
> +extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree),
> + gimple_match_simplify_fn, bitmap = nullptr);
> +extern bool fold_stmt_inplace (gimple_stmt_iterator *,
> + tree (*) (tree) = no_follow_ssa_edges,
> + gimple_match_simplify_fn = gimple_simplify);
> extern tree maybe_fold_and_comparisons (tree, enum tree_code, tree, tree,
> enum tree_code, tree, tree,
> - basic_block = nullptr);
> + basic_block = nullptr,
> + gimple_match_simplify_fn =
> gimple_simplify);
> extern tree maybe_fold_or_comparisons (tree, enum tree_code, tree, tree,
> enum tree_code, tree, tree,
> - basic_block = nullptr);
> + basic_block = nullptr,
> + gimple_match_simplify_fn =
> gimple_simplify);
> extern bool optimize_atomic_compare_exchange_p (gimple *);
> extern void fold_builtin_atomic_compare_exchange (gimple_stmt_iterator *);
> extern tree gimple_fold_stmt_to_constant_1 (gimple *, tree (*) (tree),
> - tree (*) (tree) =
> no_follow_ssa_edges);
> + tree (*) (tree) =
> no_follow_ssa_edges,
> + gimple_match_simplify_fn
> + = gimple_simplify);
> extern tree gimple_fold_stmt_to_constant (gimple *, tree (*) (tree));
> extern tree fold_ctor_reference (tree, tree, const poly_uint64&,
> const poly_uint64&, tree,
>
>
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)