summaryrefslogtreecommitdiff
path: root/system/gcc/match-split.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/gcc/match-split.patch')
-rw-r--r--system/gcc/match-split.patch3583
1 files changed, 3583 insertions, 0 deletions
diff --git a/system/gcc/match-split.patch b/system/gcc/match-split.patch
new file mode 100644
index 000000000..afb357b1d
--- /dev/null
+++ b/system/gcc/match-split.patch
@@ -0,0 +1,3583 @@
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109927#c21
+
+From 49ed8cead428b48bf46afbbb37a4d043d00702d6 Mon Sep 17 00:00:00 2001
+From: Tamar Christina <tamar.christina@arm.com>
+Date: Fri, 5 May 2023 13:37:49 +0100
+Subject: [PATCH 04/15] genmatch: split shared code to gimple-match-exports.cc
+
+In preparation for automatically splitting match.pd files I split off the
+non-static helper functions that are shared between the match.pd functions off
+to another file.
+
+This file can be compiled in parallel and also allows us to later avoid
+duplicate symbols errors.
+
+gcc/ChangeLog:
+
+ PR bootstrap/84402
+ * Makefile.in (OBJS): Add gimple-match-exports.o.
+ * genmatch.cc (decision_tree::gen): Export gimple_gimplify helpers.
+ * gimple-match-head.cc (gimple_simplify, gimple_resimplify1,
+ gimple_resimplify2, gimple_resimplify3, gimple_resimplify4,
+ gimple_resimplify5, constant_for_folding, convert_conditional_op,
+ maybe_resimplify_conditional_op, gimple_match_op::resimplify,
+ maybe_build_generic_op, build_call_internal, maybe_push_res_to_seq,
+ do_valueize, try_conditional_simplification, gimple_extract,
+ gimple_extract_op, canonicalize_code, commutative_binary_op_p,
+ commutative_ternary_op_p, first_commutative_argument,
+ associative_binary_op_p, directly_supported_p,
+ get_conditional_internal_fn): Moved to gimple-match-exports.cc
+ * gimple-match-exports.cc: New file.
+
+(cherry picked from commit 27fcf994c5515e1bbf2ff03d28fd2fa927c7e7b5)
+---
+ gcc/Makefile.in | 4 +-
+ gcc/genmatch.cc | 4 +-
+ gcc/gimple-match-exports.cc | 1253 +++++++++++++++++++++++++++++++++++
+ gcc/gimple-match-head.cc | 1192 +--------------------------------
+ 4 files changed, 1260 insertions(+), 1193 deletions(-)
+ create mode 100644 gcc/gimple-match-exports.cc
+
+diff --git a/gcc/Makefile.in b/gcc/Makefile.in
+index 06d192fa9ed8..406856acde1c 100644
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -223,6 +223,7 @@ libgcov-util.o-warn = -Wno-error
+ libgcov-driver-tool.o-warn = -Wno-error
+ libgcov-merge-tool.o-warn = -Wno-error
+ gimple-match.o-warn = -Wno-unused
++gimple-match-exports.o-warn = -Wno-unused
+ generic-match.o-warn = -Wno-unused
+ dfp.o-warn = -Wno-strict-aliasing
+
+@@ -1312,6 +1313,7 @@ ANALYZER_OBJS = \
+ # the last objects to finish building.
+ OBJS = \
+ gimple-match.o \
++ gimple-match-exports.o \
+ generic-match.o \
+ insn-attrtab.o \
+ insn-automata.o \
+@@ -2663,7 +2665,7 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
+ false; \
+ fi
+
+-gimple-match.cc: s-match gimple-match-head.cc ; @true
++gimple-match.cc: s-match gimple-match-head.cc gimple-match-exports.cc ; @true
+ generic-match.cc: s-match generic-match-head.cc ; @true
+
+ s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd cfn-operators.pd
+diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc
+index a17ef8a23ed5..665d7e2106ff 100644
+--- a/gcc/genmatch.cc
++++ b/gcc/genmatch.cc
+@@ -3957,7 +3957,7 @@ decision_tree::gen (FILE *f, bool gimple)
+ if (! has_kids_p)
+ {
+ if (gimple)
+- fprintf (f, "\nstatic bool\n"
++ fprintf (f, "\nbool\n"
+ "gimple_simplify (gimple_match_op*, gimple_seq*,\n"
+ " tree (*)(tree), code_helper,\n"
+ " const tree");
+@@ -3980,7 +3980,7 @@ decision_tree::gen (FILE *f, bool gimple)
+ /* Then generate the main entry with the outermost switch and
+ tail-calls to the split-out functions. */
+ if (gimple)
+- fprintf (f, "\nstatic bool\n"
++ fprintf (f, "\nbool\n"
+ "gimple_simplify (gimple_match_op *res_op, gimple_seq *seq,\n"
+ " tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
+ " code_helper code, const tree type");
+diff --git a/gcc/gimple-match-exports.cc b/gcc/gimple-match-exports.cc
+new file mode 100644
+index 000000000000..7aeb4ddb1524
+--- /dev/null
++++ b/gcc/gimple-match-exports.cc
+@@ -0,0 +1,1253 @@
++/* Helpers for the autogenerated gimple-match.cc file.
++ Copyright (C) 2023 Free Software Foundation, Inc.
++
++This file is part of GCC.
++
++GCC is free software; you can redistribute it and/or modify it under
++the terms of the GNU General Public License as published by the Free
++Software Foundation; either version 3, or (at your option) any later
++version.
++
++GCC is distributed in the hope that it will be useful, but WITHOUT ANY
++WARRANTY; without even the implied warranty of MERCHANTABILITY or
++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++for more details.
++
++You should have received a copy of the GNU General Public License
++along with GCC; see the file COPYING3. If not see
++<http://www.gnu.org/licenses/>. */
++
++#include "config.h"
++#include "system.h"
++#include "coretypes.h"
++#include "backend.h"
++#include "target.h"
++#include "rtl.h"
++#include "tree.h"
++#include "gimple.h"
++#include "ssa.h"
++#include "cgraph.h"
++#include "vec-perm-indices.h"
++#include "fold-const.h"
++#include "fold-const-call.h"
++#include "stor-layout.h"
++#include "gimple-iterator.h"
++#include "gimple-fold.h"
++#include "calls.h"
++#include "tree-dfa.h"
++#include "builtins.h"
++#include "gimple-match.h"
++#include "tree-pass.h"
++#include "internal-fn.h"
++#include "case-cfn-macros.h"
++#include "gimplify.h"
++#include "optabs-tree.h"
++#include "tree-eh.h"
++#include "dbgcnt.h"
++#include "tm.h"
++#include "gimple-range.h"
++#include "langhooks.h"
++
++tree (*mprts_hook) (gimple_match_op *);
++
++extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
++ code_helper, tree, tree);
++extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
++ code_helper, tree, tree, tree);
++extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
++ code_helper, tree, tree, tree, tree);
++extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
++ code_helper, tree, tree, tree, tree, tree);
++extern bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
++ code_helper, tree, tree, tree, tree, tree, tree);
++
++/* Functions that are needed by gimple-match but that are exported and used in
++ other places in the compiler. */
++
++tree gimple_simplify (enum tree_code, tree, tree, gimple_seq *,
++ tree (*)(tree));
++tree gimple_simplify (enum tree_code, tree, tree, tree, gimple_seq *,
++ tree (*)(tree));
++tree gimple_simplify (enum tree_code, tree, tree, tree, tree, gimple_seq *,
++ tree (*)(tree));
++tree gimple_simplify (combined_fn, tree, tree, gimple_seq *,
++ tree (*)(tree));
++tree gimple_simplify (combined_fn, tree, tree, tree, gimple_seq *,
++ tree (*)(tree));
++tree gimple_simplify (combined_fn, tree, tree, tree, tree, gimple_seq *,
++ tree (*)(tree));
++
++tree do_valueize (tree, tree (*)(tree), bool &);
++tree do_valueize (tree (*)(tree), tree);
++
++/* Forward declarations of the private auto-generated matchers.
++ They expect valueized operands in canonical order and do not
++ perform simplification of all-constant operands. */
++
++static bool gimple_resimplify1 (gimple_seq *, gimple_match_op *, tree (*)(tree));
++static bool gimple_resimplify2 (gimple_seq *, gimple_match_op *, tree (*)(tree));
++static bool gimple_resimplify3 (gimple_seq *, gimple_match_op *, tree (*)(tree));
++static bool gimple_resimplify4 (gimple_seq *, gimple_match_op *, tree (*)(tree));
++static bool gimple_resimplify5 (gimple_seq *, gimple_match_op *, tree (*)(tree));
++
++/* Match and simplify the toplevel valueized operation THIS.
++ Replaces THIS with a simplified and/or canonicalized result and
++ returns whether any change was made. */
++
++bool
++gimple_match_op::resimplify (gimple_seq *seq, tree (*valueize)(tree))
++{
++ switch (num_ops)
++ {
++ case 1:
++ return gimple_resimplify1 (seq, this, valueize);
++ case 2:
++ return gimple_resimplify2 (seq, this, valueize);
++ case 3:
++ return gimple_resimplify3 (seq, this, valueize);
++ case 4:
++ return gimple_resimplify4 (seq, this, valueize);
++ case 5:
++ return gimple_resimplify5 (seq, this, valueize);
++ default:
++ gcc_unreachable ();
++ }
++}
++
++/* Return whether T is a constant that we'll dispatch to fold to
++ evaluate fully constant expressions. */
++
++static inline bool
++constant_for_folding (tree t)
++{
++ return (CONSTANT_CLASS_P (t)
++ /* The following is only interesting to string builtins. */
++ || (TREE_CODE (t) == ADDR_EXPR
++ && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST));
++}
++
++/* Try to convert conditional operation ORIG_OP into an IFN_COND_*
++ operation. Return true on success, storing the new operation in NEW_OP. */
++
++static bool
++convert_conditional_op (gimple_match_op *orig_op,
++ gimple_match_op *new_op)
++{
++ internal_fn ifn;
++ if (orig_op->code.is_tree_code ())
++ ifn = get_conditional_internal_fn ((tree_code) orig_op->code);
++ else
++ {
++ auto cfn = combined_fn (orig_op->code);
++ if (!internal_fn_p (cfn))
++ return false;
++ ifn = get_conditional_internal_fn (as_internal_fn (cfn));
++ }
++ if (ifn == IFN_LAST)
++ return false;
++ unsigned int num_ops = orig_op->num_ops;
++ new_op->set_op (as_combined_fn (ifn), orig_op->type, num_ops + 2);
++ new_op->ops[0] = orig_op->cond.cond;
++ for (unsigned int i = 0; i < num_ops; ++i)
++ new_op->ops[i + 1] = orig_op->ops[i];
++ tree else_value = orig_op->cond.else_value;
++ if (!else_value)
++ else_value = targetm.preferred_else_value (ifn, orig_op->type,
++ num_ops, orig_op->ops);
++ new_op->ops[num_ops + 1] = else_value;
++ return true;
++}
++/* Helper for gimple_simplify valueizing OP using VALUEIZE and setting
++ VALUEIZED to true if valueization changed OP. */
++
++inline tree
++do_valueize (tree op, tree (*valueize)(tree), bool &valueized)
++{
++ if (valueize && TREE_CODE (op) == SSA_NAME)
++ {
++ tree tem = valueize (op);
++ if (tem && tem != op)
++ {
++ op = tem;
++ valueized = true;
++ }
++ }
++ return op;
++}
++
++/* If in GIMPLE the operation described by RES_OP should be single-rhs,
++ build a GENERIC tree for that expression and update RES_OP accordingly. */
++
++void
++maybe_build_generic_op (gimple_match_op *res_op)
++{
++ tree_code code = (tree_code) res_op->code;
++ tree val;
++ switch (code)
++ {
++ case REALPART_EXPR:
++ case IMAGPART_EXPR:
++ case VIEW_CONVERT_EXPR:
++ val = build1 (code, res_op->type, res_op->ops[0]);
++ res_op->set_value (val);
++ break;
++ case BIT_FIELD_REF:
++ val = build3 (code, res_op->type, res_op->ops[0], res_op->ops[1],
++ res_op->ops[2]);
++ REF_REVERSE_STORAGE_ORDER (val) = res_op->reverse;
++ res_op->set_value (val);
++ break;
++ default:;
++ }
++}
++
++/* Try to build RES_OP, which is known to be a call to FN. Return null
++ if the target doesn't support the function. */
++
++static gcall *
++build_call_internal (internal_fn fn, gimple_match_op *res_op)
++{
++ if (direct_internal_fn_p (fn))
++ {
++ tree_pair types = direct_internal_fn_types (fn, res_op->type,
++ res_op->ops);
++ if (!direct_internal_fn_supported_p (fn, types, OPTIMIZE_FOR_BOTH))
++ return NULL;
++ }
++ return gimple_build_call_internal (fn, res_op->num_ops,
++ res_op->op_or_null (0),
++ res_op->op_or_null (1),
++ res_op->op_or_null (2),
++ res_op->op_or_null (3),
++ res_op->op_or_null (4));
++}
++
++/* RES_OP is the result of a simplification. If it is conditional,
++ try to replace it with the equivalent UNCOND form, such as an
++ IFN_COND_* call or a VEC_COND_EXPR. Also try to resimplify the
++ result of the replacement if appropriate, adding any new statements to
++ SEQ and using VALUEIZE as the valueization function. Return true if
++ this resimplification occurred and resulted in at least one change. */
++
++static bool
++maybe_resimplify_conditional_op (gimple_seq *seq, gimple_match_op *res_op,
++ tree (*valueize) (tree))
++{
++ if (!res_op->cond.cond)
++ return false;
++
++ if (!res_op->cond.else_value
++ && res_op->code.is_tree_code ())
++ {
++ /* The "else" value doesn't matter. If the "then" value is a
++ gimple value, just use it unconditionally. This isn't a
++ simplification in itself, since there was no operation to
++ build in the first place. */
++ if (gimple_simplified_result_is_gimple_val (res_op))
++ {
++ res_op->cond.cond = NULL_TREE;
++ return false;
++ }
++
++ /* Likewise if the operation would not trap. */
++ bool honor_trapv = (INTEGRAL_TYPE_P (res_op->type)
++ && TYPE_OVERFLOW_TRAPS (res_op->type));
++ tree_code op_code = (tree_code) res_op->code;
++ bool op_could_trap;
++
++ /* COND_EXPR will trap if, and only if, the condition
++ traps and hence we have to check this. For all other operations, we
++ don't need to consider the operands. */
++ if (op_code == COND_EXPR)
++ op_could_trap = generic_expr_could_trap_p (res_op->ops[0]);
++ else
++ op_could_trap = operation_could_trap_p ((tree_code) res_op->code,
++ FLOAT_TYPE_P (res_op->type),
++ honor_trapv,
++ res_op->op_or_null (1));
++
++ if (!op_could_trap)
++ {
++ res_op->cond.cond = NULL_TREE;
++ return false;
++ }
++ }
++
++ /* If the "then" value is a gimple value and the "else" value matters,
++ create a VEC_COND_EXPR between them, then see if it can be further
++ simplified. */
++ gimple_match_op new_op;
++ if (res_op->cond.else_value
++ && VECTOR_TYPE_P (res_op->type)
++ && gimple_simplified_result_is_gimple_val (res_op))
++ {
++ new_op.set_op (VEC_COND_EXPR, res_op->type,
++ res_op->cond.cond, res_op->ops[0],
++ res_op->cond.else_value);
++ *res_op = new_op;
++ return gimple_resimplify3 (seq, res_op, valueize);
++ }
++
++ /* Otherwise try rewriting the operation as an IFN_COND_* call.
++ Again, this isn't a simplification in itself, since it's what
++ RES_OP already described. */
++ if (convert_conditional_op (res_op, &new_op))
++ *res_op = new_op;
++
++ return false;
++}
++
++/* If RES_OP is a call to a conditional internal function, try simplifying
++ the associated unconditional operation and using the result to build
++ a new conditional operation. For example, if RES_OP is:
++
++ IFN_COND_ADD (COND, A, B, ELSE)
++
++ try simplifying (plus A B) and using the result to build a replacement
++ for the whole IFN_COND_ADD.
++
++ Return true if this approach led to a simplification, otherwise leave
++ RES_OP unchanged (and so suitable for other simplifications). When
++ returning true, add any new statements to SEQ and use VALUEIZE as the
++ valueization function.
++
++ RES_OP is known to be a call to IFN. */
++
++static bool
++try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op,
++ gimple_seq *seq, tree (*valueize) (tree))
++{
++ code_helper op;
++ tree_code code = conditional_internal_fn_code (ifn);
++ if (code != ERROR_MARK)
++ op = code;
++ else
++ {
++ ifn = get_unconditional_internal_fn (ifn);
++ if (ifn == IFN_LAST)
++ return false;
++ op = as_combined_fn (ifn);
++ }
++
++ unsigned int num_ops = res_op->num_ops;
++ gimple_match_op cond_op (gimple_match_cond (res_op->ops[0],
++ res_op->ops[num_ops - 1]),
++ op, res_op->type, num_ops - 2);
++
++ memcpy (cond_op.ops, res_op->ops + 1, (num_ops - 1) * sizeof *cond_op.ops);
++ switch (num_ops - 2)
++ {
++ case 1:
++ if (!gimple_resimplify1 (seq, &cond_op, valueize))
++ return false;
++ break;
++ case 2:
++ if (!gimple_resimplify2 (seq, &cond_op, valueize))
++ return false;
++ break;
++ case 3:
++ if (!gimple_resimplify3 (seq, &cond_op, valueize))
++ return false;
++ break;
++ default:
++ gcc_unreachable ();
++ }
++ *res_op = cond_op;
++ maybe_resimplify_conditional_op (seq, res_op, valueize);
++ return true;
++}
++
++/* Helper for the autogenerated code, valueize OP. */
++
++tree
++do_valueize (tree (*valueize)(tree), tree op)
++{
++ if (valueize && TREE_CODE (op) == SSA_NAME)
++ {
++ tree tem = valueize (op);
++ if (tem)
++ return tem;
++ }
++ return op;
++}
++
++/* Push the exploded expression described by RES_OP as a statement to
++ SEQ if necessary and return a gimple value denoting the value of the
++ expression. If RES is not NULL then the result will be always RES
++ and even gimple values are pushed to SEQ. */
++
++tree
++maybe_push_res_to_seq (gimple_match_op *res_op, gimple_seq *seq, tree res)
++{
++ tree *ops = res_op->ops;
++ unsigned num_ops = res_op->num_ops;
++
++ /* The caller should have converted conditional operations into an UNCOND
++ form and resimplified as appropriate. The conditional form only
++ survives this far if that conversion failed. */
++ if (res_op->cond.cond)
++ return NULL_TREE;
++
++ if (res_op->code.is_tree_code ())
++ {
++ if (!res
++ && gimple_simplified_result_is_gimple_val (res_op))
++ return ops[0];
++ if (mprts_hook)
++ {
++ tree tem = mprts_hook (res_op);
++ if (tem)
++ return tem;
++ }
++ }
++
++ if (!seq)
++ return NULL_TREE;
++
++ /* Play safe and do not allow abnormals to be mentioned in
++ newly created statements. */
++ for (unsigned int i = 0; i < num_ops; ++i)
++ if (TREE_CODE (ops[i]) == SSA_NAME
++ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[i]))
++ return NULL_TREE;
++
++ if (num_ops > 0 && COMPARISON_CLASS_P (ops[0]))
++ for (unsigned int i = 0; i < 2; ++i)
++ if (TREE_CODE (TREE_OPERAND (ops[0], i)) == SSA_NAME
++ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], i)))
++ return NULL_TREE;
++
++ if (res_op->code.is_tree_code ())
++ {
++ auto code = tree_code (res_op->code);
++ if (!res)
++ {
++ if (gimple_in_ssa_p (cfun))
++ res = make_ssa_name (res_op->type);
++ else
++ res = create_tmp_reg (res_op->type);
++ }
++ maybe_build_generic_op (res_op);
++ gimple *new_stmt = gimple_build_assign (res, code,
++ res_op->op_or_null (0),
++ res_op->op_or_null (1),
++ res_op->op_or_null (2));
++ gimple_seq_add_stmt_without_update (seq, new_stmt);
++ return res;
++ }
++ else
++ {
++ gcc_assert (num_ops != 0);
++ auto fn = combined_fn (res_op->code);
++ gcall *new_stmt = NULL;
++ if (internal_fn_p (fn))
++ {
++ /* Generate the given function if we can. */
++ internal_fn ifn = as_internal_fn (fn);
++ new_stmt = build_call_internal (ifn, res_op);
++ if (!new_stmt)
++ return NULL_TREE;
++ }
++ else
++ {
++ /* Find the function we want to call. */
++ tree decl = builtin_decl_implicit (as_builtin_fn (fn));
++ if (!decl)
++ return NULL;
++
++ /* We can't and should not emit calls to non-const functions. */
++ if (!(flags_from_decl_or_type (decl) & ECF_CONST))
++ return NULL;
++
++ new_stmt = gimple_build_call (decl, num_ops,
++ res_op->op_or_null (0),
++ res_op->op_or_null (1),
++ res_op->op_or_null (2),
++ res_op->op_or_null (3),
++ res_op->op_or_null (4));
++ }
++ if (!res)
++ {
++ if (gimple_in_ssa_p (cfun))
++ res = make_ssa_name (res_op->type);
++ else
++ res = create_tmp_reg (res_op->type);
++ }
++ gimple_call_set_lhs (new_stmt, res);
++ gimple_seq_add_stmt_without_update (seq, new_stmt);
++ return res;
++ }
++}
++
++
++/* Public API overloads follow for operation being tree_code or
++ built_in_function and for one to three operands or arguments.
++ They return NULL_TREE if nothing could be simplified or
++ the resulting simplified value with parts pushed to SEQ.
++ If SEQ is NULL then if the simplification needs to create
++ new stmts it will fail. If VALUEIZE is non-NULL then all
++ SSA names will be valueized using that hook prior to
++ applying simplifications. */
++
++/* Unary ops. */
++
++tree
++gimple_simplify (enum tree_code code, tree type,
++ tree op0,
++ gimple_seq *seq, tree (*valueize)(tree))
++{
++ if (constant_for_folding (op0))
++ {
++ tree res = const_unop (code, type, op0);
++ if (res != NULL_TREE
++ && CONSTANT_CLASS_P (res))
++ return res;
++ }
++
++ gimple_match_op res_op;
++ if (!gimple_simplify (&res_op, seq, valueize, code, type, op0))
++ return NULL_TREE;
++ return maybe_push_res_to_seq (&res_op, seq);
++}
++
++/* Binary ops. */
++
++tree
++gimple_simplify (enum tree_code code, tree type,
++ tree op0, tree op1,
++ gimple_seq *seq, tree (*valueize)(tree))
++{
++ if (constant_for_folding (op0) && constant_for_folding (op1))
++ {
++ tree res = const_binop (code, type, op0, op1);
++ if (res != NULL_TREE
++ && CONSTANT_CLASS_P (res))
++ return res;
++ }
++
++ /* Canonicalize operand order both for matching and fallback stmt
++ generation. */
++ if ((commutative_tree_code (code)
++ || TREE_CODE_CLASS (code) == tcc_comparison)
++ && tree_swap_operands_p (op0, op1))
++ {
++ std::swap (op0, op1);
++ if (TREE_CODE_CLASS (code) == tcc_comparison)
++ code = swap_tree_comparison (code);
++ }
++
++ gimple_match_op res_op;
++ if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1))
++ return NULL_TREE;
++ return maybe_push_res_to_seq (&res_op, seq);
++}
++
++/* Ternary ops. */
++
++tree
++gimple_simplify (enum tree_code code, tree type,
++ tree op0, tree op1, tree op2,
++ gimple_seq *seq, tree (*valueize)(tree))
++{
++ if (constant_for_folding (op0) && constant_for_folding (op1)
++ && constant_for_folding (op2))
++ {
++ tree res = fold_ternary/*_to_constant */ (code, type, op0, op1, op2);
++ if (res != NULL_TREE
++ && CONSTANT_CLASS_P (res))
++ return res;
++ }
++
++ /* Canonicalize operand order both for matching and fallback stmt
++ generation. */
++ if (commutative_ternary_tree_code (code)
++ && tree_swap_operands_p (op0, op1))
++ std::swap (op0, op1);
++
++ gimple_match_op res_op;
++ if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1, op2))
++ return NULL_TREE;
++ return maybe_push_res_to_seq (&res_op, seq);
++}
++
++/* Builtin or internal function with one argument. */
++
++tree
++gimple_simplify (combined_fn fn, tree type,
++ tree arg0,
++ gimple_seq *seq, tree (*valueize)(tree))
++{
++ if (constant_for_folding (arg0))
++ {
++ tree res = fold_const_call (fn, type, arg0);
++ if (res && CONSTANT_CLASS_P (res))
++ return res;
++ }
++
++ gimple_match_op res_op;
++ if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0))
++ return NULL_TREE;
++ return maybe_push_res_to_seq (&res_op, seq);
++}
++
++/* Builtin or internal function with two arguments. */
++
++tree
++gimple_simplify (combined_fn fn, tree type,
++ tree arg0, tree arg1,
++ gimple_seq *seq, tree (*valueize)(tree))
++{
++ if (constant_for_folding (arg0)
++ && constant_for_folding (arg1))
++ {
++ tree res = fold_const_call (fn, type, arg0, arg1);
++ if (res && CONSTANT_CLASS_P (res))
++ return res;
++ }
++
++ gimple_match_op res_op;
++ if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1))
++ return NULL_TREE;
++ return maybe_push_res_to_seq (&res_op, seq);
++}
++
++/* Builtin or internal function with three arguments. */
++
++tree
++gimple_simplify (combined_fn fn, tree type,
++ tree arg0, tree arg1, tree arg2,
++ gimple_seq *seq, tree (*valueize)(tree))
++{
++ if (constant_for_folding (arg0)
++ && constant_for_folding (arg1)
++ && constant_for_folding (arg2))
++ {
++ tree res = fold_const_call (fn, type, arg0, arg1, arg2);
++ if (res && CONSTANT_CLASS_P (res))
++ return res;
++ }
++
++ gimple_match_op res_op;
++ if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1, arg2))
++ return NULL_TREE;
++ return maybe_push_res_to_seq (&res_op, seq);
++}
++
++/* Common subroutine of gimple_extract_op and gimple_simplify. Try to
++ describe STMT in RES_OP, returning true on success. Before recording
++ an operand, call:
++
++ - VALUEIZE_CONDITION for a COND_EXPR condition
++ - VALUEIZE_OP for every other top-level operand
++
++ Both routines take a tree argument and returns a tree. */
++
++template<typename ValueizeOp, typename ValueizeCondition>
++inline bool
++gimple_extract (gimple *stmt, gimple_match_op *res_op,
++ ValueizeOp valueize_op,
++ ValueizeCondition valueize_condition)
++{
++ switch (gimple_code (stmt))
++ {
++ case GIMPLE_ASSIGN:
++ {
++ enum tree_code code = gimple_assign_rhs_code (stmt);
++ tree type = TREE_TYPE (gimple_assign_lhs (stmt));
++ switch (gimple_assign_rhs_class (stmt))
++ {
++ case GIMPLE_SINGLE_RHS:
++ if (code == REALPART_EXPR
++ || code == IMAGPART_EXPR
++ || code == VIEW_CONVERT_EXPR)
++ {
++ tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
++ res_op->set_op (code, type, valueize_op (op0));
++ return true;
++ }
++ else if (code == BIT_FIELD_REF)
++ {
++ tree rhs1 = gimple_assign_rhs1 (stmt);
++ tree op0 = valueize_op (TREE_OPERAND (rhs1, 0));
++ res_op->set_op (code, type, op0,
++ TREE_OPERAND (rhs1, 1),
++ TREE_OPERAND (rhs1, 2),
++ REF_REVERSE_STORAGE_ORDER (rhs1));
++ return true;
++ }
++ else if (code == SSA_NAME)
++ {
++ tree op0 = gimple_assign_rhs1 (stmt);
++ res_op->set_op (TREE_CODE (op0), type, valueize_op (op0));
++ return true;
++ }
++ break;
++ case GIMPLE_UNARY_RHS:
++ {
++ tree rhs1 = gimple_assign_rhs1 (stmt);
++ res_op->set_op (code, type, valueize_op (rhs1));
++ return true;
++ }
++ case GIMPLE_BINARY_RHS:
++ {
++ tree rhs1 = valueize_op (gimple_assign_rhs1 (stmt));
++ tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt));
++ res_op->set_op (code, type, rhs1, rhs2);
++ return true;
++ }
++ case GIMPLE_TERNARY_RHS:
++ {
++ tree rhs1 = gimple_assign_rhs1 (stmt);
++ if (code == COND_EXPR && COMPARISON_CLASS_P (rhs1))
++ rhs1 = valueize_condition (rhs1);
++ else
++ rhs1 = valueize_op (rhs1);
++ tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt));
++ tree rhs3 = valueize_op (gimple_assign_rhs3 (stmt));
++ res_op->set_op (code, type, rhs1, rhs2, rhs3);
++ return true;
++ }
++ default:
++ gcc_unreachable ();
++ }
++ break;
++ }
++
++ case GIMPLE_CALL:
++ /* ??? This way we can't simplify calls with side-effects. */
++ if (gimple_call_lhs (stmt) != NULL_TREE
++ && gimple_call_num_args (stmt) >= 1
++ && gimple_call_num_args (stmt) <= 5)
++ {
++ combined_fn cfn;
++ if (gimple_call_internal_p (stmt))
++ cfn = as_combined_fn (gimple_call_internal_fn (stmt));
++ else
++ {
++ tree fn = gimple_call_fn (stmt);
++ if (!fn)
++ return false;
++
++ fn = valueize_op (fn);
++ if (TREE_CODE (fn) != ADDR_EXPR
++ || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
++ return false;
++
++ tree decl = TREE_OPERAND (fn, 0);
++ if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL
++ || !gimple_builtin_call_types_compatible_p (stmt, decl))
++ return false;
++
++ cfn = as_combined_fn (DECL_FUNCTION_CODE (decl));
++ }
++
++ unsigned int num_args = gimple_call_num_args (stmt);
++ res_op->set_op (cfn, TREE_TYPE (gimple_call_lhs (stmt)), num_args);
++ for (unsigned i = 0; i < num_args; ++i)
++ res_op->ops[i] = valueize_op (gimple_call_arg (stmt, i));
++ return true;
++ }
++ break;
++
++ case GIMPLE_COND:
++ {
++ tree lhs = valueize_op (gimple_cond_lhs (stmt));
++ tree rhs = valueize_op (gimple_cond_rhs (stmt));
++ res_op->set_op (gimple_cond_code (stmt), boolean_type_node, lhs, rhs);
++ return true;
++ }
++
++ default:
++ break;
++ }
++
++ return false;
++}
++
++/* Try to describe STMT in RES_OP, returning true on success.
++ For GIMPLE_CONDs, describe the condition that is being tested.
++ For GIMPLE_ASSIGNs, describe the rhs of the assignment.
++ For GIMPLE_CALLs, describe the call. */
++
++bool
++gimple_extract_op (gimple *stmt, gimple_match_op *res_op)
++{
++ auto nop = [](tree op) { return op; };
++ return gimple_extract (stmt, res_op, nop, nop);
++}
++
++/* The main STMT based simplification entry. It is used by the fold_stmt
++ and the fold_stmt_to_constant APIs. */
++
++bool
++gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq,
++ tree (*valueize)(tree), tree (*top_valueize)(tree))
++{
++ bool valueized = false;
++ auto valueize_op = [&](tree op)
++ {
++ return do_valueize (op, top_valueize, valueized);
++ };
++ auto valueize_condition = [&](tree op) -> tree
++ {
++ bool cond_valueized = false;
++ tree lhs = do_valueize (TREE_OPERAND (op, 0), top_valueize,
++ cond_valueized);
++ tree rhs = do_valueize (TREE_OPERAND (op, 1), top_valueize,
++ cond_valueized);
++ gimple_match_op res_op2 (res_op->cond, TREE_CODE (op),
++ TREE_TYPE (op), lhs, rhs);
++ if ((gimple_resimplify2 (seq, &res_op2, valueize)
++ || cond_valueized)
++ && res_op2.code.is_tree_code ())
++ {
++ auto code = tree_code (res_op2.code);
++ if (TREE_CODE_CLASS (code) == tcc_comparison)
++ {
++ valueized = true;
++ return build2 (code, TREE_TYPE (op),
++ res_op2.ops[0], res_op2.ops[1]);
++ }
++ else if (code == SSA_NAME
++ || code == INTEGER_CST
++ || code == VECTOR_CST)
++ {
++ valueized = true;
++ return res_op2.ops[0];
++ }
++ }
++ return valueize_op (op);
++ };
++
++ if (!gimple_extract (stmt, res_op, valueize_op, valueize_condition))
++ return false;
++
++ if (res_op->code.is_internal_fn ())
++ {
++ internal_fn ifn = internal_fn (res_op->code);
++ if (try_conditional_simplification (ifn, res_op, seq, valueize))
++ return true;
++ }
++
++ if (!res_op->reverse
++ && res_op->num_ops
++ && res_op->resimplify (seq, valueize))
++ return true;
++
++ return valueized;
++}
++
++/* Helper that matches and simplifies the toplevel result from
++ a gimple_simplify run (where we don't want to build
++ a stmt in case it's used in in-place folding). Replaces
++ RES_OP with a simplified and/or canonicalized result and
++ returns whether any change was made. */
++
++static bool
++gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
++ tree (*valueize)(tree))
++{
++ if (constant_for_folding (res_op->ops[0]))
++ {
++ tree tem = NULL_TREE;
++ if (res_op->code.is_tree_code ())
++ {
++ auto code = tree_code (res_op->code);
++ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
++ && TREE_CODE_LENGTH (code) == 1)
++ tem = const_unop (code, res_op->type, res_op->ops[0]);
++ }
++ else
++ tem = fold_const_call (combined_fn (res_op->code), res_op->type,
++ res_op->ops[0]);
++ if (tem != NULL_TREE
++ && CONSTANT_CLASS_P (tem))
++ {
++ if (TREE_OVERFLOW_P (tem))
++ tem = drop_tree_overflow (tem);
++ res_op->set_value (tem);
++ maybe_resimplify_conditional_op (seq, res_op, valueize);
++ return true;
++ }
++ }
++
++ /* Limit recursion, there are cases like PR80887 and others, for
++ example when value-numbering presents us with unfolded expressions
++ that we are really not prepared to handle without eventual
++ oscillation like ((_50 + 0) + 8) where _50 gets mapped to _50
++ itself as available expression. */
++ static unsigned depth;
++ if (depth > 10)
++ {
++ if (dump_file && (dump_flags & TDF_FOLDING))
++ fprintf (dump_file, "Aborting expression simplification due to "
++ "deep recursion\n");
++ return false;
++ }
++
++ ++depth;
++ gimple_match_op res_op2 (*res_op);
++ if (gimple_simplify (&res_op2, seq, valueize,
++ res_op->code, res_op->type, res_op->ops[0]))
++ {
++ --depth;
++ *res_op = res_op2;
++ return true;
++ }
++ --depth;
++
++ if (maybe_resimplify_conditional_op (seq, res_op, valueize))
++ return true;
++
++ return false;
++}
++
++/* Helper that matches and simplifies the toplevel result from
++ a gimple_simplify run (where we don't want to build
++ a stmt in case it's used in in-place folding). Replaces
++ RES_OP with a simplified and/or canonicalized result and
++ returns whether any change was made. */
++
++static bool
++gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
++ tree (*valueize)(tree))
++{
++ if (constant_for_folding (res_op->ops[0])
++ && constant_for_folding (res_op->ops[1]))
++ {
++ tree tem = NULL_TREE;
++ if (res_op->code.is_tree_code ())
++ {
++ auto code = tree_code (res_op->code);
++ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
++ && TREE_CODE_LENGTH (code) == 2)
++ tem = const_binop (code, res_op->type,
++ res_op->ops[0], res_op->ops[1]);
++ }
++ else
++ tem = fold_const_call (combined_fn (res_op->code), res_op->type,
++ res_op->ops[0], res_op->ops[1]);
++ if (tem != NULL_TREE
++ && CONSTANT_CLASS_P (tem))
++ {
++ if (TREE_OVERFLOW_P (tem))
++ tem = drop_tree_overflow (tem);
++ res_op->set_value (tem);
++ maybe_resimplify_conditional_op (seq, res_op, valueize);
++ return true;
++ }
++ }
++
++ /* Canonicalize operand order. */
++ bool canonicalized = false;
++ bool is_comparison
++ = (res_op->code.is_tree_code ()
++ && TREE_CODE_CLASS (tree_code (res_op->code)) == tcc_comparison);
++ if ((is_comparison || commutative_binary_op_p (res_op->code, res_op->type))
++ && tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
++ {
++ std::swap (res_op->ops[0], res_op->ops[1]);
++ if (is_comparison)
++ res_op->code = swap_tree_comparison (tree_code (res_op->code));
++ canonicalized = true;
++ }
++
++ /* Limit recursion, see gimple_resimplify1. */
++ static unsigned depth;
++ if (depth > 10)
++ {
++ if (dump_file && (dump_flags & TDF_FOLDING))
++ fprintf (dump_file, "Aborting expression simplification due to "
++ "deep recursion\n");
++ return false;
++ }
++
++ ++depth;
++ gimple_match_op res_op2 (*res_op);
++ if (gimple_simplify (&res_op2, seq, valueize,
++ res_op->code, res_op->type,
++ res_op->ops[0], res_op->ops[1]))
++ {
++ --depth;
++ *res_op = res_op2;
++ return true;
++ }
++ --depth;
++
++ if (maybe_resimplify_conditional_op (seq, res_op, valueize))
++ return true;
++
++ return canonicalized;
++}
++
++/* Helper that matches and simplifies the toplevel result from
++ a gimple_simplify run (where we don't want to build
++ a stmt in case it's used in in-place folding). Replaces
++ RES_OP with a simplified and/or canonicalized result and
++ returns whether any change was made. */
++
++static bool
++gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
++ tree (*valueize)(tree))
++{
++ if (constant_for_folding (res_op->ops[0])
++ && constant_for_folding (res_op->ops[1])
++ && constant_for_folding (res_op->ops[2]))
++ {
++ tree tem = NULL_TREE;
++ if (res_op->code.is_tree_code ())
++ {
++ auto code = tree_code (res_op->code);
++ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
++ && TREE_CODE_LENGTH (code) == 3)
++ tem = fold_ternary/*_to_constant*/ (code, res_op->type,
++ res_op->ops[0], res_op->ops[1],
++ res_op->ops[2]);
++ }
++ else
++ tem = fold_const_call (combined_fn (res_op->code), res_op->type,
++ res_op->ops[0], res_op->ops[1], res_op->ops[2]);
++ if (tem != NULL_TREE
++ && CONSTANT_CLASS_P (tem))
++ {
++ if (TREE_OVERFLOW_P (tem))
++ tem = drop_tree_overflow (tem);
++ res_op->set_value (tem);
++ maybe_resimplify_conditional_op (seq, res_op, valueize);
++ return true;
++ }
++ }
++
++ /* Canonicalize operand order. */
++ bool canonicalized = false;
++ int argno = first_commutative_argument (res_op->code, res_op->type);
++ if (argno >= 0
++ && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
++ {
++ std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
++ canonicalized = true;
++ }
++
++ /* Limit recursion, see gimple_resimplify1. */
++ static unsigned depth;
++ if (depth > 10)
++ {
++ if (dump_file && (dump_flags & TDF_FOLDING))
++ fprintf (dump_file, "Aborting expression simplification due to "
++ "deep recursion\n");
++ return false;
++ }
++
++ ++depth;
++ gimple_match_op res_op2 (*res_op);
++ if (gimple_simplify (&res_op2, seq, valueize,
++ res_op->code, res_op->type,
++ res_op->ops[0], res_op->ops[1], res_op->ops[2]))
++ {
++ --depth;
++ *res_op = res_op2;
++ return true;
++ }
++ --depth;
++
++ if (maybe_resimplify_conditional_op (seq, res_op, valueize))
++ return true;
++
++ return canonicalized;
++}
++
++/* Helper that matches and simplifies the toplevel result from
++ a gimple_simplify run (where we don't want to build
++ a stmt in case it's used in in-place folding). Replaces
++ RES_OP with a simplified and/or canonicalized result and
++ returns whether any change was made. */
++
++static bool
++gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
++ tree (*valueize)(tree))
++{
++ /* No constant folding is defined for four-operand functions. */
++
++ /* Canonicalize operand order. */
++ bool canonicalized = false;
++ int argno = first_commutative_argument (res_op->code, res_op->type);
++ if (argno >= 0
++ && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
++ {
++ std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
++ canonicalized = true;
++ }
++
++ /* Limit recursion, see gimple_resimplify1. */
++ static unsigned depth;
++ if (depth > 10)
++ {
++ if (dump_file && (dump_flags & TDF_FOLDING))
++ fprintf (dump_file, "Aborting expression simplification due to "
++ "deep recursion\n");
++ return false;
++ }
++
++ ++depth;
++ gimple_match_op res_op2 (*res_op);
++ if (gimple_simplify (&res_op2, seq, valueize,
++ res_op->code, res_op->type,
++ res_op->ops[0], res_op->ops[1], res_op->ops[2],
++ res_op->ops[3]))
++ {
++ --depth;
++ *res_op = res_op2;
++ return true;
++ }
++ --depth;
++
++ if (maybe_resimplify_conditional_op (seq, res_op, valueize))
++ return true;
++
++ return canonicalized;
++}
++
++/* Helper that matches and simplifies the toplevel result from
++ a gimple_simplify run (where we don't want to build
++ a stmt in case it's used in in-place folding). Replaces
++ RES_OP with a simplified and/or canonicalized result and
++ returns whether any change was made. */
++
++static bool
++gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op,
++ tree (*valueize)(tree))
++{
++ /* No constant folding is defined for five-operand functions. */
++
++ /* Canonicalize operand order. */
++ bool canonicalized = false;
++ int argno = first_commutative_argument (res_op->code, res_op->type);
++ if (argno >= 0
++ && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
++ {
++ std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
++ canonicalized = true;
++ }
++
++ gimple_match_op res_op2 (*res_op);
++ if (gimple_simplify (&res_op2, seq, valueize,
++ res_op->code, res_op->type,
++ res_op->ops[0], res_op->ops[1], res_op->ops[2],
++ res_op->ops[3], res_op->ops[4]))
++ {
++ *res_op = res_op2;
++ return true;
++ }
++
++ if (maybe_resimplify_conditional_op (seq, res_op, valueize))
++ return true;
++
++ return canonicalized;
++}
++
++/* Return a canonical form for CODE when operating on TYPE. The idea
++ is to remove redundant ways of representing the same operation so
++ that code_helpers can be hashed and compared for equality.
++
++ The only current canonicalization is to replace built-in functions
++ with internal functions, in cases where internal-fn.def defines
++ such an internal function.
++
++ Note that the new code_helper cannot necessarily be used in place of
++ the original code_helper. For example, the new code_helper might be
++ an internal function that the target does not support. */
++
++code_helper
++canonicalize_code (code_helper code, tree type)
++{
++ if (code.is_fn_code ())
++ return associated_internal_fn (combined_fn (code), type);
++ return code;
++}
++
++/* Return true if CODE is a binary operation and if CODE is commutative when
++ operating on type TYPE. */
++
++bool
++commutative_binary_op_p (code_helper code, tree type)
++{
++ if (code.is_tree_code ())
++ return commutative_tree_code (tree_code (code));
++ auto cfn = combined_fn (code);
++ return commutative_binary_fn_p (associated_internal_fn (cfn, type));
++}
++
++/* Return true if CODE represents a ternary operation and if the first two
++ operands are commutative when CODE is operating on TYPE. */
++
++bool
++commutative_ternary_op_p (code_helper code, tree type)
++{
++ if (code.is_tree_code ())
++ return commutative_ternary_tree_code (tree_code (code));
++ auto cfn = combined_fn (code);
++ return commutative_ternary_fn_p (associated_internal_fn (cfn, type));
++}
++
++/* If CODE is commutative in two consecutive operands, return the
++ index of the first, otherwise return -1. */
++
++int
++first_commutative_argument (code_helper code, tree type)
++{
++ if (code.is_tree_code ())
++ {
++ auto tcode = tree_code (code);
++ if (commutative_tree_code (tcode)
++ || commutative_ternary_tree_code (tcode))
++ return 0;
++ return -1;
++ }
++ auto cfn = combined_fn (code);
++ return first_commutative_argument (associated_internal_fn (cfn, type));
++}
++
++/* Return true if CODE is a binary operation that is associative when
++ operating on type TYPE. */
++
++bool
++associative_binary_op_p (code_helper code, tree type)
++{
++ if (code.is_tree_code ())
++ return associative_tree_code (tree_code (code));
++ auto cfn = combined_fn (code);
++ return associative_binary_fn_p (associated_internal_fn (cfn, type));
++}
++
++/* Return true if the target directly supports operation CODE on type TYPE.
++ QUERY_TYPE acts as for optab_for_tree_code. */
++
++bool
++directly_supported_p (code_helper code, tree type, optab_subtype query_type)
++{
++ if (code.is_tree_code ())
++ {
++ direct_optab optab = optab_for_tree_code (tree_code (code), type,
++ query_type);
++ return (optab != unknown_optab
++ && optab_handler (optab, TYPE_MODE (type)) != CODE_FOR_nothing);
++ }
++ gcc_assert (query_type == optab_default
++ || (query_type == optab_vector && VECTOR_TYPE_P (type))
++ || (query_type == optab_scalar && !VECTOR_TYPE_P (type)));
++ internal_fn ifn = associated_internal_fn (combined_fn (code), type);
++ return (direct_internal_fn_p (ifn)
++ && direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED));
++}
++
++/* A wrapper around the internal-fn.cc versions of get_conditional_internal_fn
++ for a code_helper CODE operating on type TYPE. */
++
++internal_fn
++get_conditional_internal_fn (code_helper code, tree type)
++{
++ if (code.is_tree_code ())
++ return get_conditional_internal_fn (tree_code (code));
++ auto cfn = combined_fn (code);
++ return get_conditional_internal_fn (associated_internal_fn (cfn, type));
++}
+diff --git a/gcc/gimple-match-head.cc b/gcc/gimple-match-head.cc
+index 21843d7870b3..3069ff5cb6e1 100644
+--- a/gcc/gimple-match-head.cc
++++ b/gcc/gimple-match-head.cc
+@@ -50,1089 +50,8 @@ along with GCC; see the file COPYING3. If not see
+ #include "attribs.h"
+ #include "asan.h"
+
+-/* Forward declarations of the private auto-generated matchers.
+- They expect valueized operands in canonical order and do not
+- perform simplification of all-constant operands. */
+-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+- code_helper, tree, tree);
+-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+- code_helper, tree, tree, tree);
+-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+- code_helper, tree, tree, tree, tree);
+-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+- code_helper, tree, tree, tree, tree, tree);
+-static bool gimple_simplify (gimple_match_op *, gimple_seq *, tree (*)(tree),
+- code_helper, tree, tree, tree, tree, tree, tree);
+-static bool gimple_resimplify1 (gimple_seq *, gimple_match_op *,
+- tree (*)(tree));
+-static bool gimple_resimplify2 (gimple_seq *, gimple_match_op *,
+- tree (*)(tree));
+-static bool gimple_resimplify3 (gimple_seq *, gimple_match_op *,
+- tree (*)(tree));
+-static bool gimple_resimplify4 (gimple_seq *, gimple_match_op *,
+- tree (*)(tree));
+-static bool gimple_resimplify5 (gimple_seq *, gimple_match_op *,
+- tree (*)(tree));
+-
+-const unsigned int gimple_match_op::MAX_NUM_OPS;
+-
+-/* Return whether T is a constant that we'll dispatch to fold to
+- evaluate fully constant expressions. */
+-
+-static inline bool
+-constant_for_folding (tree t)
+-{
+- return (CONSTANT_CLASS_P (t)
+- /* The following is only interesting to string builtins. */
+- || (TREE_CODE (t) == ADDR_EXPR
+- && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST));
+-}
+-
+-/* Try to convert conditional operation ORIG_OP into an IFN_COND_*
+- operation. Return true on success, storing the new operation in NEW_OP. */
+-
+-static bool
+-convert_conditional_op (gimple_match_op *orig_op,
+- gimple_match_op *new_op)
+-{
+- internal_fn ifn;
+- if (orig_op->code.is_tree_code ())
+- ifn = get_conditional_internal_fn ((tree_code) orig_op->code);
+- else
+- {
+- auto cfn = combined_fn (orig_op->code);
+- if (!internal_fn_p (cfn))
+- return false;
+- ifn = get_conditional_internal_fn (as_internal_fn (cfn));
+- }
+- if (ifn == IFN_LAST)
+- return false;
+- unsigned int num_ops = orig_op->num_ops;
+- new_op->set_op (as_combined_fn (ifn), orig_op->type, num_ops + 2);
+- new_op->ops[0] = orig_op->cond.cond;
+- for (unsigned int i = 0; i < num_ops; ++i)
+- new_op->ops[i + 1] = orig_op->ops[i];
+- tree else_value = orig_op->cond.else_value;
+- if (!else_value)
+- else_value = targetm.preferred_else_value (ifn, orig_op->type,
+- num_ops, orig_op->ops);
+- new_op->ops[num_ops + 1] = else_value;
+- return true;
+-}
+-
+-/* RES_OP is the result of a simplification. If it is conditional,
+- try to replace it with the equivalent UNCOND form, such as an
+- IFN_COND_* call or a VEC_COND_EXPR. Also try to resimplify the
+- result of the replacement if appropriate, adding any new statements to
+- SEQ and using VALUEIZE as the valueization function. Return true if
+- this resimplification occurred and resulted in at least one change. */
+-
+-static bool
+-maybe_resimplify_conditional_op (gimple_seq *seq, gimple_match_op *res_op,
+- tree (*valueize) (tree))
+-{
+- if (!res_op->cond.cond)
+- return false;
+-
+- if (!res_op->cond.else_value
+- && res_op->code.is_tree_code ())
+- {
+- /* The "else" value doesn't matter. If the "then" value is a
+- gimple value, just use it unconditionally. This isn't a
+- simplification in itself, since there was no operation to
+- build in the first place. */
+- if (gimple_simplified_result_is_gimple_val (res_op))
+- {
+- res_op->cond.cond = NULL_TREE;
+- return false;
+- }
+-
+- /* Likewise if the operation would not trap. */
+- bool honor_trapv = (INTEGRAL_TYPE_P (res_op->type)
+- && TYPE_OVERFLOW_TRAPS (res_op->type));
+- tree_code op_code = (tree_code) res_op->code;
+- bool op_could_trap;
+-
+- /* COND_EXPR will trap if, and only if, the condition
+- traps and hence we have to check this. For all other operations, we
+- don't need to consider the operands. */
+- if (op_code == COND_EXPR)
+- op_could_trap = generic_expr_could_trap_p (res_op->ops[0]);
+- else
+- op_could_trap = operation_could_trap_p ((tree_code) res_op->code,
+- FLOAT_TYPE_P (res_op->type),
+- honor_trapv,
+- res_op->op_or_null (1));
+-
+- if (!op_could_trap)
+- {
+- res_op->cond.cond = NULL_TREE;
+- return false;
+- }
+- }
+-
+- /* If the "then" value is a gimple value and the "else" value matters,
+- create a VEC_COND_EXPR between them, then see if it can be further
+- simplified. */
+- gimple_match_op new_op;
+- if (res_op->cond.else_value
+- && VECTOR_TYPE_P (res_op->type)
+- && gimple_simplified_result_is_gimple_val (res_op))
+- {
+- new_op.set_op (VEC_COND_EXPR, res_op->type,
+- res_op->cond.cond, res_op->ops[0],
+- res_op->cond.else_value);
+- *res_op = new_op;
+- return gimple_resimplify3 (seq, res_op, valueize);
+- }
+-
+- /* Otherwise try rewriting the operation as an IFN_COND_* call.
+- Again, this isn't a simplification in itself, since it's what
+- RES_OP already described. */
+- if (convert_conditional_op (res_op, &new_op))
+- *res_op = new_op;
+-
+- return false;
+-}
+-
+-/* Helper that matches and simplifies the toplevel result from
+- a gimple_simplify run (where we don't want to build
+- a stmt in case it's used in in-place folding). Replaces
+- RES_OP with a simplified and/or canonicalized result and
+- returns whether any change was made. */
+-
+-static bool
+-gimple_resimplify1 (gimple_seq *seq, gimple_match_op *res_op,
+- tree (*valueize)(tree))
+-{
+- if (constant_for_folding (res_op->ops[0]))
+- {
+- tree tem = NULL_TREE;
+- if (res_op->code.is_tree_code ())
+- {
+- auto code = tree_code (res_op->code);
+- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+- && TREE_CODE_LENGTH (code) == 1)
+- tem = const_unop (code, res_op->type, res_op->ops[0]);
+- }
+- else
+- tem = fold_const_call (combined_fn (res_op->code), res_op->type,
+- res_op->ops[0]);
+- if (tem != NULL_TREE
+- && CONSTANT_CLASS_P (tem))
+- {
+- if (TREE_OVERFLOW_P (tem))
+- tem = drop_tree_overflow (tem);
+- res_op->set_value (tem);
+- maybe_resimplify_conditional_op (seq, res_op, valueize);
+- return true;
+- }
+- }
+-
+- /* Limit recursion, there are cases like PR80887 and others, for
+- example when value-numbering presents us with unfolded expressions
+- that we are really not prepared to handle without eventual
+- oscillation like ((_50 + 0) + 8) where _50 gets mapped to _50
+- itself as available expression. */
+- static unsigned depth;
+- if (depth > 10)
+- {
+- if (dump_file && (dump_flags & TDF_FOLDING))
+- fprintf (dump_file, "Aborting expression simplification due to "
+- "deep recursion\n");
+- return false;
+- }
+-
+- ++depth;
+- gimple_match_op res_op2 (*res_op);
+- if (gimple_simplify (&res_op2, seq, valueize,
+- res_op->code, res_op->type, res_op->ops[0]))
+- {
+- --depth;
+- *res_op = res_op2;
+- return true;
+- }
+- --depth;
+-
+- if (maybe_resimplify_conditional_op (seq, res_op, valueize))
+- return true;
+-
+- return false;
+-}
+-
+-/* Helper that matches and simplifies the toplevel result from
+- a gimple_simplify run (where we don't want to build
+- a stmt in case it's used in in-place folding). Replaces
+- RES_OP with a simplified and/or canonicalized result and
+- returns whether any change was made. */
+-
+-static bool
+-gimple_resimplify2 (gimple_seq *seq, gimple_match_op *res_op,
+- tree (*valueize)(tree))
+-{
+- if (constant_for_folding (res_op->ops[0])
+- && constant_for_folding (res_op->ops[1]))
+- {
+- tree tem = NULL_TREE;
+- if (res_op->code.is_tree_code ())
+- {
+- auto code = tree_code (res_op->code);
+- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+- && TREE_CODE_LENGTH (code) == 2)
+- tem = const_binop (code, res_op->type,
+- res_op->ops[0], res_op->ops[1]);
+- }
+- else
+- tem = fold_const_call (combined_fn (res_op->code), res_op->type,
+- res_op->ops[0], res_op->ops[1]);
+- if (tem != NULL_TREE
+- && CONSTANT_CLASS_P (tem))
+- {
+- if (TREE_OVERFLOW_P (tem))
+- tem = drop_tree_overflow (tem);
+- res_op->set_value (tem);
+- maybe_resimplify_conditional_op (seq, res_op, valueize);
+- return true;
+- }
+- }
+-
+- /* Canonicalize operand order. */
+- bool canonicalized = false;
+- bool is_comparison
+- = (res_op->code.is_tree_code ()
+- && TREE_CODE_CLASS (tree_code (res_op->code)) == tcc_comparison);
+- if ((is_comparison || commutative_binary_op_p (res_op->code, res_op->type))
+- && tree_swap_operands_p (res_op->ops[0], res_op->ops[1]))
+- {
+- std::swap (res_op->ops[0], res_op->ops[1]);
+- if (is_comparison)
+- res_op->code = swap_tree_comparison (tree_code (res_op->code));
+- canonicalized = true;
+- }
+-
+- /* Limit recursion, see gimple_resimplify1. */
+- static unsigned depth;
+- if (depth > 10)
+- {
+- if (dump_file && (dump_flags & TDF_FOLDING))
+- fprintf (dump_file, "Aborting expression simplification due to "
+- "deep recursion\n");
+- return false;
+- }
+-
+- ++depth;
+- gimple_match_op res_op2 (*res_op);
+- if (gimple_simplify (&res_op2, seq, valueize,
+- res_op->code, res_op->type,
+- res_op->ops[0], res_op->ops[1]))
+- {
+- --depth;
+- *res_op = res_op2;
+- return true;
+- }
+- --depth;
+-
+- if (maybe_resimplify_conditional_op (seq, res_op, valueize))
+- return true;
+-
+- return canonicalized;
+-}
+-
+-/* Helper that matches and simplifies the toplevel result from
+- a gimple_simplify run (where we don't want to build
+- a stmt in case it's used in in-place folding). Replaces
+- RES_OP with a simplified and/or canonicalized result and
+- returns whether any change was made. */
+-
+-static bool
+-gimple_resimplify3 (gimple_seq *seq, gimple_match_op *res_op,
+- tree (*valueize)(tree))
+-{
+- if (constant_for_folding (res_op->ops[0])
+- && constant_for_folding (res_op->ops[1])
+- && constant_for_folding (res_op->ops[2]))
+- {
+- tree tem = NULL_TREE;
+- if (res_op->code.is_tree_code ())
+- {
+- auto code = tree_code (res_op->code);
+- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+- && TREE_CODE_LENGTH (code) == 3)
+- tem = fold_ternary/*_to_constant*/ (code, res_op->type,
+- res_op->ops[0], res_op->ops[1],
+- res_op->ops[2]);
+- }
+- else
+- tem = fold_const_call (combined_fn (res_op->code), res_op->type,
+- res_op->ops[0], res_op->ops[1], res_op->ops[2]);
+- if (tem != NULL_TREE
+- && CONSTANT_CLASS_P (tem))
+- {
+- if (TREE_OVERFLOW_P (tem))
+- tem = drop_tree_overflow (tem);
+- res_op->set_value (tem);
+- maybe_resimplify_conditional_op (seq, res_op, valueize);
+- return true;
+- }
+- }
+-
+- /* Canonicalize operand order. */
+- bool canonicalized = false;
+- int argno = first_commutative_argument (res_op->code, res_op->type);
+- if (argno >= 0
+- && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
+- {
+- std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
+- canonicalized = true;
+- }
+-
+- /* Limit recursion, see gimple_resimplify1. */
+- static unsigned depth;
+- if (depth > 10)
+- {
+- if (dump_file && (dump_flags & TDF_FOLDING))
+- fprintf (dump_file, "Aborting expression simplification due to "
+- "deep recursion\n");
+- return false;
+- }
+-
+- ++depth;
+- gimple_match_op res_op2 (*res_op);
+- if (gimple_simplify (&res_op2, seq, valueize,
+- res_op->code, res_op->type,
+- res_op->ops[0], res_op->ops[1], res_op->ops[2]))
+- {
+- --depth;
+- *res_op = res_op2;
+- return true;
+- }
+- --depth;
+-
+- if (maybe_resimplify_conditional_op (seq, res_op, valueize))
+- return true;
+-
+- return canonicalized;
+-}
+-
+-/* Helper that matches and simplifies the toplevel result from
+- a gimple_simplify run (where we don't want to build
+- a stmt in case it's used in in-place folding). Replaces
+- RES_OP with a simplified and/or canonicalized result and
+- returns whether any change was made. */
+-
+-static bool
+-gimple_resimplify4 (gimple_seq *seq, gimple_match_op *res_op,
+- tree (*valueize)(tree))
+-{
+- /* No constant folding is defined for four-operand functions. */
+-
+- /* Canonicalize operand order. */
+- bool canonicalized = false;
+- int argno = first_commutative_argument (res_op->code, res_op->type);
+- if (argno >= 0
+- && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
+- {
+- std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
+- canonicalized = true;
+- }
+-
+- /* Limit recursion, see gimple_resimplify1. */
+- static unsigned depth;
+- if (depth > 10)
+- {
+- if (dump_file && (dump_flags & TDF_FOLDING))
+- fprintf (dump_file, "Aborting expression simplification due to "
+- "deep recursion\n");
+- return false;
+- }
+-
+- ++depth;
+- gimple_match_op res_op2 (*res_op);
+- if (gimple_simplify (&res_op2, seq, valueize,
+- res_op->code, res_op->type,
+- res_op->ops[0], res_op->ops[1], res_op->ops[2],
+- res_op->ops[3]))
+- {
+- --depth;
+- *res_op = res_op2;
+- return true;
+- }
+- --depth;
+-
+- if (maybe_resimplify_conditional_op (seq, res_op, valueize))
+- return true;
+-
+- return canonicalized;
+-}
+-
+-/* Helper that matches and simplifies the toplevel result from
+- a gimple_simplify run (where we don't want to build
+- a stmt in case it's used in in-place folding). Replaces
+- RES_OP with a simplified and/or canonicalized result and
+- returns whether any change was made. */
+-
+-static bool
+-gimple_resimplify5 (gimple_seq *seq, gimple_match_op *res_op,
+- tree (*valueize)(tree))
+-{
+- /* No constant folding is defined for five-operand functions. */
+-
+- /* Canonicalize operand order. */
+- bool canonicalized = false;
+- int argno = first_commutative_argument (res_op->code, res_op->type);
+- if (argno >= 0
+- && tree_swap_operands_p (res_op->ops[argno], res_op->ops[argno + 1]))
+- {
+- std::swap (res_op->ops[argno], res_op->ops[argno + 1]);
+- canonicalized = true;
+- }
+-
+- gimple_match_op res_op2 (*res_op);
+- if (gimple_simplify (&res_op2, seq, valueize,
+- res_op->code, res_op->type,
+- res_op->ops[0], res_op->ops[1], res_op->ops[2],
+- res_op->ops[3], res_op->ops[4]))
+- {
+- *res_op = res_op2;
+- return true;
+- }
+-
+- if (maybe_resimplify_conditional_op (seq, res_op, valueize))
+- return true;
+-
+- return canonicalized;
+-}
+-
+-/* Match and simplify the toplevel valueized operation THIS.
+- Replaces THIS with a simplified and/or canonicalized result and
+- returns whether any change was made. */
+-
+-bool
+-gimple_match_op::resimplify (gimple_seq *seq, tree (*valueize)(tree))
+-{
+- switch (num_ops)
+- {
+- case 1:
+- return gimple_resimplify1 (seq, this, valueize);
+- case 2:
+- return gimple_resimplify2 (seq, this, valueize);
+- case 3:
+- return gimple_resimplify3 (seq, this, valueize);
+- case 4:
+- return gimple_resimplify4 (seq, this, valueize);
+- case 5:
+- return gimple_resimplify5 (seq, this, valueize);
+- default:
+- gcc_unreachable ();
+- }
+-}
+-
+-/* If in GIMPLE the operation described by RES_OP should be single-rhs,
+- build a GENERIC tree for that expression and update RES_OP accordingly. */
+-
+-void
+-maybe_build_generic_op (gimple_match_op *res_op)
+-{
+- tree_code code = (tree_code) res_op->code;
+- tree val;
+- switch (code)
+- {
+- case REALPART_EXPR:
+- case IMAGPART_EXPR:
+- case VIEW_CONVERT_EXPR:
+- val = build1 (code, res_op->type, res_op->ops[0]);
+- res_op->set_value (val);
+- break;
+- case BIT_FIELD_REF:
+- val = build3 (code, res_op->type, res_op->ops[0], res_op->ops[1],
+- res_op->ops[2]);
+- REF_REVERSE_STORAGE_ORDER (val) = res_op->reverse;
+- res_op->set_value (val);
+- break;
+- default:;
+- }
+-}
+-
+-tree (*mprts_hook) (gimple_match_op *);
+-
+-/* Try to build RES_OP, which is known to be a call to FN. Return null
+- if the target doesn't support the function. */
+-
+-static gcall *
+-build_call_internal (internal_fn fn, gimple_match_op *res_op)
+-{
+- if (direct_internal_fn_p (fn))
+- {
+- tree_pair types = direct_internal_fn_types (fn, res_op->type,
+- res_op->ops);
+- if (!direct_internal_fn_supported_p (fn, types, OPTIMIZE_FOR_BOTH))
+- return NULL;
+- }
+- return gimple_build_call_internal (fn, res_op->num_ops,
+- res_op->op_or_null (0),
+- res_op->op_or_null (1),
+- res_op->op_or_null (2),
+- res_op->op_or_null (3),
+- res_op->op_or_null (4));
+-}
+-
+-/* Push the exploded expression described by RES_OP as a statement to
+- SEQ if necessary and return a gimple value denoting the value of the
+- expression. If RES is not NULL then the result will be always RES
+- and even gimple values are pushed to SEQ. */
+-
+-tree
+-maybe_push_res_to_seq (gimple_match_op *res_op, gimple_seq *seq, tree res)
+-{
+- tree *ops = res_op->ops;
+- unsigned num_ops = res_op->num_ops;
+-
+- /* The caller should have converted conditional operations into an UNCOND
+- form and resimplified as appropriate. The conditional form only
+- survives this far if that conversion failed. */
+- if (res_op->cond.cond)
+- return NULL_TREE;
+-
+- if (res_op->code.is_tree_code ())
+- {
+- if (!res
+- && gimple_simplified_result_is_gimple_val (res_op))
+- return ops[0];
+- if (mprts_hook)
+- {
+- tree tem = mprts_hook (res_op);
+- if (tem)
+- return tem;
+- }
+- }
+-
+- if (!seq)
+- return NULL_TREE;
+-
+- /* Play safe and do not allow abnormals to be mentioned in
+- newly created statements. */
+- for (unsigned int i = 0; i < num_ops; ++i)
+- if (TREE_CODE (ops[i]) == SSA_NAME
+- && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[i]))
+- return NULL_TREE;
+-
+- if (num_ops > 0 && COMPARISON_CLASS_P (ops[0]))
+- for (unsigned int i = 0; i < 2; ++i)
+- if (TREE_CODE (TREE_OPERAND (ops[0], i)) == SSA_NAME
+- && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (ops[0], i)))
+- return NULL_TREE;
+-
+- if (res_op->code.is_tree_code ())
+- {
+- auto code = tree_code (res_op->code);
+- if (!res)
+- {
+- if (gimple_in_ssa_p (cfun))
+- res = make_ssa_name (res_op->type);
+- else
+- res = create_tmp_reg (res_op->type);
+- }
+- maybe_build_generic_op (res_op);
+- gimple *new_stmt = gimple_build_assign (res, code,
+- res_op->op_or_null (0),
+- res_op->op_or_null (1),
+- res_op->op_or_null (2));
+- gimple_seq_add_stmt_without_update (seq, new_stmt);
+- return res;
+- }
+- else
+- {
+- gcc_assert (num_ops != 0);
+- auto fn = combined_fn (res_op->code);
+- gcall *new_stmt = NULL;
+- if (internal_fn_p (fn))
+- {
+- /* Generate the given function if we can. */
+- internal_fn ifn = as_internal_fn (fn);
+- new_stmt = build_call_internal (ifn, res_op);
+- if (!new_stmt)
+- return NULL_TREE;
+- }
+- else
+- {
+- /* Find the function we want to call. */
+- tree decl = builtin_decl_implicit (as_builtin_fn (fn));
+- if (!decl)
+- return NULL;
+-
+- /* We can't and should not emit calls to non-const functions. */
+- if (!(flags_from_decl_or_type (decl) & ECF_CONST))
+- return NULL;
+-
+- new_stmt = gimple_build_call (decl, num_ops,
+- res_op->op_or_null (0),
+- res_op->op_or_null (1),
+- res_op->op_or_null (2),
+- res_op->op_or_null (3),
+- res_op->op_or_null (4));
+- }
+- if (!res)
+- {
+- if (gimple_in_ssa_p (cfun))
+- res = make_ssa_name (res_op->type);
+- else
+- res = create_tmp_reg (res_op->type);
+- }
+- gimple_call_set_lhs (new_stmt, res);
+- gimple_seq_add_stmt_without_update (seq, new_stmt);
+- return res;
+- }
+-}
+-
+-
+-/* Public API overloads follow for operation being tree_code or
+- built_in_function and for one to three operands or arguments.
+- They return NULL_TREE if nothing could be simplified or
+- the resulting simplified value with parts pushed to SEQ.
+- If SEQ is NULL then if the simplification needs to create
+- new stmts it will fail. If VALUEIZE is non-NULL then all
+- SSA names will be valueized using that hook prior to
+- applying simplifications. */
+-
+-/* Unary ops. */
+-
+-tree
+-gimple_simplify (enum tree_code code, tree type,
+- tree op0,
+- gimple_seq *seq, tree (*valueize)(tree))
+-{
+- if (constant_for_folding (op0))
+- {
+- tree res = const_unop (code, type, op0);
+- if (res != NULL_TREE
+- && CONSTANT_CLASS_P (res))
+- return res;
+- }
+-
+- gimple_match_op res_op;
+- if (!gimple_simplify (&res_op, seq, valueize, code, type, op0))
+- return NULL_TREE;
+- return maybe_push_res_to_seq (&res_op, seq);
+-}
+-
+-/* Binary ops. */
+-
+-tree
+-gimple_simplify (enum tree_code code, tree type,
+- tree op0, tree op1,
+- gimple_seq *seq, tree (*valueize)(tree))
+-{
+- if (constant_for_folding (op0) && constant_for_folding (op1))
+- {
+- tree res = const_binop (code, type, op0, op1);
+- if (res != NULL_TREE
+- && CONSTANT_CLASS_P (res))
+- return res;
+- }
+-
+- /* Canonicalize operand order both for matching and fallback stmt
+- generation. */
+- if ((commutative_tree_code (code)
+- || TREE_CODE_CLASS (code) == tcc_comparison)
+- && tree_swap_operands_p (op0, op1))
+- {
+- std::swap (op0, op1);
+- if (TREE_CODE_CLASS (code) == tcc_comparison)
+- code = swap_tree_comparison (code);
+- }
+-
+- gimple_match_op res_op;
+- if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1))
+- return NULL_TREE;
+- return maybe_push_res_to_seq (&res_op, seq);
+-}
+-
+-/* Ternary ops. */
+-
+-tree
+-gimple_simplify (enum tree_code code, tree type,
+- tree op0, tree op1, tree op2,
+- gimple_seq *seq, tree (*valueize)(tree))
+-{
+- if (constant_for_folding (op0) && constant_for_folding (op1)
+- && constant_for_folding (op2))
+- {
+- tree res = fold_ternary/*_to_constant */ (code, type, op0, op1, op2);
+- if (res != NULL_TREE
+- && CONSTANT_CLASS_P (res))
+- return res;
+- }
+-
+- /* Canonicalize operand order both for matching and fallback stmt
+- generation. */
+- if (commutative_ternary_tree_code (code)
+- && tree_swap_operands_p (op0, op1))
+- std::swap (op0, op1);
+-
+- gimple_match_op res_op;
+- if (!gimple_simplify (&res_op, seq, valueize, code, type, op0, op1, op2))
+- return NULL_TREE;
+- return maybe_push_res_to_seq (&res_op, seq);
+-}
+-
+-/* Builtin or internal function with one argument. */
+-
+-tree
+-gimple_simplify (combined_fn fn, tree type,
+- tree arg0,
+- gimple_seq *seq, tree (*valueize)(tree))
+-{
+- if (constant_for_folding (arg0))
+- {
+- tree res = fold_const_call (fn, type, arg0);
+- if (res && CONSTANT_CLASS_P (res))
+- return res;
+- }
+-
+- gimple_match_op res_op;
+- if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0))
+- return NULL_TREE;
+- return maybe_push_res_to_seq (&res_op, seq);
+-}
+-
+-/* Builtin or internal function with two arguments. */
+-
+-tree
+-gimple_simplify (combined_fn fn, tree type,
+- tree arg0, tree arg1,
+- gimple_seq *seq, tree (*valueize)(tree))
+-{
+- if (constant_for_folding (arg0)
+- && constant_for_folding (arg1))
+- {
+- tree res = fold_const_call (fn, type, arg0, arg1);
+- if (res && CONSTANT_CLASS_P (res))
+- return res;
+- }
+-
+- gimple_match_op res_op;
+- if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1))
+- return NULL_TREE;
+- return maybe_push_res_to_seq (&res_op, seq);
+-}
+-
+-/* Builtin or internal function with three arguments. */
+-
+-tree
+-gimple_simplify (combined_fn fn, tree type,
+- tree arg0, tree arg1, tree arg2,
+- gimple_seq *seq, tree (*valueize)(tree))
+-{
+- if (constant_for_folding (arg0)
+- && constant_for_folding (arg1)
+- && constant_for_folding (arg2))
+- {
+- tree res = fold_const_call (fn, type, arg0, arg1, arg2);
+- if (res && CONSTANT_CLASS_P (res))
+- return res;
+- }
+-
+- gimple_match_op res_op;
+- if (!gimple_simplify (&res_op, seq, valueize, fn, type, arg0, arg1, arg2))
+- return NULL_TREE;
+- return maybe_push_res_to_seq (&res_op, seq);
+-}
+-
+-/* Helper for gimple_simplify valueizing OP using VALUEIZE and setting
+- VALUEIZED to true if valueization changed OP. */
+-
+-static inline tree
+-do_valueize (tree op, tree (*valueize)(tree), bool &valueized)
+-{
+- if (valueize && TREE_CODE (op) == SSA_NAME)
+- {
+- tree tem = valueize (op);
+- if (tem && tem != op)
+- {
+- op = tem;
+- valueized = true;
+- }
+- }
+- return op;
+-}
+-
+-/* If RES_OP is a call to a conditional internal function, try simplifying
+- the associated unconditional operation and using the result to build
+- a new conditional operation. For example, if RES_OP is:
+-
+- IFN_COND_ADD (COND, A, B, ELSE)
+-
+- try simplifying (plus A B) and using the result to build a replacement
+- for the whole IFN_COND_ADD.
+-
+- Return true if this approach led to a simplification, otherwise leave
+- RES_OP unchanged (and so suitable for other simplifications). When
+- returning true, add any new statements to SEQ and use VALUEIZE as the
+- valueization function.
+-
+- RES_OP is known to be a call to IFN. */
+-
+-static bool
+-try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op,
+- gimple_seq *seq, tree (*valueize) (tree))
+-{
+- code_helper op;
+- tree_code code = conditional_internal_fn_code (ifn);
+- if (code != ERROR_MARK)
+- op = code;
+- else
+- {
+- ifn = get_unconditional_internal_fn (ifn);
+- if (ifn == IFN_LAST)
+- return false;
+- op = as_combined_fn (ifn);
+- }
+-
+- unsigned int num_ops = res_op->num_ops;
+- gimple_match_op cond_op (gimple_match_cond (res_op->ops[0],
+- res_op->ops[num_ops - 1]),
+- op, res_op->type, num_ops - 2);
+-
+- memcpy (cond_op.ops, res_op->ops + 1, (num_ops - 1) * sizeof *cond_op.ops);
+- switch (num_ops - 2)
+- {
+- case 1:
+- if (!gimple_resimplify1 (seq, &cond_op, valueize))
+- return false;
+- break;
+- case 2:
+- if (!gimple_resimplify2 (seq, &cond_op, valueize))
+- return false;
+- break;
+- case 3:
+- if (!gimple_resimplify3 (seq, &cond_op, valueize))
+- return false;
+- break;
+- default:
+- gcc_unreachable ();
+- }
+- *res_op = cond_op;
+- maybe_resimplify_conditional_op (seq, res_op, valueize);
+- return true;
+-}
+-
+-/* Common subroutine of gimple_extract_op and gimple_simplify. Try to
+- describe STMT in RES_OP, returning true on success. Before recording
+- an operand, call:
+-
+- - VALUEIZE_CONDITION for a COND_EXPR condition
+- - VALUEIZE_OP for every other top-level operand
+-
+- Both routines take a tree argument and returns a tree. */
+-
+-template<typename ValueizeOp, typename ValueizeCondition>
+-inline bool
+-gimple_extract (gimple *stmt, gimple_match_op *res_op,
+- ValueizeOp valueize_op,
+- ValueizeCondition valueize_condition)
+-{
+- switch (gimple_code (stmt))
+- {
+- case GIMPLE_ASSIGN:
+- {
+- enum tree_code code = gimple_assign_rhs_code (stmt);
+- tree type = TREE_TYPE (gimple_assign_lhs (stmt));
+- switch (gimple_assign_rhs_class (stmt))
+- {
+- case GIMPLE_SINGLE_RHS:
+- if (code == REALPART_EXPR
+- || code == IMAGPART_EXPR
+- || code == VIEW_CONVERT_EXPR)
+- {
+- tree op0 = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
+- res_op->set_op (code, type, valueize_op (op0));
+- return true;
+- }
+- else if (code == BIT_FIELD_REF)
+- {
+- tree rhs1 = gimple_assign_rhs1 (stmt);
+- tree op0 = valueize_op (TREE_OPERAND (rhs1, 0));
+- res_op->set_op (code, type, op0,
+- TREE_OPERAND (rhs1, 1),
+- TREE_OPERAND (rhs1, 2),
+- REF_REVERSE_STORAGE_ORDER (rhs1));
+- return true;
+- }
+- else if (code == SSA_NAME)
+- {
+- tree op0 = gimple_assign_rhs1 (stmt);
+- res_op->set_op (TREE_CODE (op0), type, valueize_op (op0));
+- return true;
+- }
+- break;
+- case GIMPLE_UNARY_RHS:
+- {
+- tree rhs1 = gimple_assign_rhs1 (stmt);
+- res_op->set_op (code, type, valueize_op (rhs1));
+- return true;
+- }
+- case GIMPLE_BINARY_RHS:
+- {
+- tree rhs1 = valueize_op (gimple_assign_rhs1 (stmt));
+- tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt));
+- res_op->set_op (code, type, rhs1, rhs2);
+- return true;
+- }
+- case GIMPLE_TERNARY_RHS:
+- {
+- tree rhs1 = gimple_assign_rhs1 (stmt);
+- if (code == COND_EXPR && COMPARISON_CLASS_P (rhs1))
+- rhs1 = valueize_condition (rhs1);
+- else
+- rhs1 = valueize_op (rhs1);
+- tree rhs2 = valueize_op (gimple_assign_rhs2 (stmt));
+- tree rhs3 = valueize_op (gimple_assign_rhs3 (stmt));
+- res_op->set_op (code, type, rhs1, rhs2, rhs3);
+- return true;
+- }
+- default:
+- gcc_unreachable ();
+- }
+- break;
+- }
+-
+- case GIMPLE_CALL:
+- /* ??? This way we can't simplify calls with side-effects. */
+- if (gimple_call_lhs (stmt) != NULL_TREE
+- && gimple_call_num_args (stmt) >= 1
+- && gimple_call_num_args (stmt) <= 5)
+- {
+- combined_fn cfn;
+- if (gimple_call_internal_p (stmt))
+- cfn = as_combined_fn (gimple_call_internal_fn (stmt));
+- else
+- {
+- tree fn = gimple_call_fn (stmt);
+- if (!fn)
+- return false;
+-
+- fn = valueize_op (fn);
+- if (TREE_CODE (fn) != ADDR_EXPR
+- || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL)
+- return false;
+-
+- tree decl = TREE_OPERAND (fn, 0);
+- if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL
+- || !gimple_builtin_call_types_compatible_p (stmt, decl))
+- return false;
+-
+- cfn = as_combined_fn (DECL_FUNCTION_CODE (decl));
+- }
+-
+- unsigned int num_args = gimple_call_num_args (stmt);
+- res_op->set_op (cfn, TREE_TYPE (gimple_call_lhs (stmt)), num_args);
+- for (unsigned i = 0; i < num_args; ++i)
+- res_op->ops[i] = valueize_op (gimple_call_arg (stmt, i));
+- return true;
+- }
+- break;
+-
+- case GIMPLE_COND:
+- {
+- tree lhs = valueize_op (gimple_cond_lhs (stmt));
+- tree rhs = valueize_op (gimple_cond_rhs (stmt));
+- res_op->set_op (gimple_cond_code (stmt), boolean_type_node, lhs, rhs);
+- return true;
+- }
+-
+- default:
+- break;
+- }
+-
+- return false;
+-}
+-
+-/* Try to describe STMT in RES_OP, returning true on success.
+- For GIMPLE_CONDs, describe the condition that is being tested.
+- For GIMPLE_ASSIGNs, describe the rhs of the assignment.
+- For GIMPLE_CALLs, describe the call. */
+-
+-bool
+-gimple_extract_op (gimple *stmt, gimple_match_op *res_op)
+-{
+- auto nop = [](tree op) { return op; };
+- return gimple_extract (stmt, res_op, nop, nop);
+-}
+-
+-/* The main STMT based simplification entry. It is used by the fold_stmt
+- and the fold_stmt_to_constant APIs. */
+-
+-bool
+-gimple_simplify (gimple *stmt, gimple_match_op *res_op, gimple_seq *seq,
+- tree (*valueize)(tree), tree (*top_valueize)(tree))
+-{
+- bool valueized = false;
+- auto valueize_op = [&](tree op)
+- {
+- return do_valueize (op, top_valueize, valueized);
+- };
+- auto valueize_condition = [&](tree op) -> tree
+- {
+- bool cond_valueized = false;
+- tree lhs = do_valueize (TREE_OPERAND (op, 0), top_valueize,
+- cond_valueized);
+- tree rhs = do_valueize (TREE_OPERAND (op, 1), top_valueize,
+- cond_valueized);
+- gimple_match_op res_op2 (res_op->cond, TREE_CODE (op),
+- TREE_TYPE (op), lhs, rhs);
+- if ((gimple_resimplify2 (seq, &res_op2, valueize)
+- || cond_valueized)
+- && res_op2.code.is_tree_code ())
+- {
+- auto code = tree_code (res_op2.code);
+- if (TREE_CODE_CLASS (code) == tcc_comparison)
+- {
+- valueized = true;
+- return build2 (code, TREE_TYPE (op),
+- res_op2.ops[0], res_op2.ops[1]);
+- }
+- else if (code == SSA_NAME
+- || code == INTEGER_CST
+- || code == VECTOR_CST)
+- {
+- valueized = true;
+- return res_op2.ops[0];
+- }
+- }
+- return valueize_op (op);
+- };
+-
+- if (!gimple_extract (stmt, res_op, valueize_op, valueize_condition))
+- return false;
+-
+- if (res_op->code.is_internal_fn ())
+- {
+- internal_fn ifn = internal_fn (res_op->code);
+- if (try_conditional_simplification (ifn, res_op, seq, valueize))
+- return true;
+- }
+-
+- if (!res_op->reverse
+- && res_op->num_ops
+- && res_op->resimplify (seq, valueize))
+- return true;
+-
+- return valueized;
+-}
+-
+-/* Helper for the autogenerated code, valueize OP. */
+-
+-inline tree
+-do_valueize (tree (*valueize)(tree), tree op)
+-{
+- if (valueize && TREE_CODE (op) == SSA_NAME)
+- {
+- tree tem = valueize (op);
+- if (tem)
+- return tem;
+- }
+- return op;
+-}
++tree do_valueize (tree, tree (*)(tree), bool &);
++tree do_valueize (tree (*)(tree), tree);
+
+ /* Helper for the autogenerated code, get at the definition of NAME when
+ VALUEIZE allows that. */
+@@ -1307,110 +226,3 @@ optimize_successive_divisions_p (tree divisor, tree inner_div)
+ }
+ return true;
+ }
+-
+-/* Return a canonical form for CODE when operating on TYPE. The idea
+- is to remove redundant ways of representing the same operation so
+- that code_helpers can be hashed and compared for equality.
+-
+- The only current canonicalization is to replace built-in functions
+- with internal functions, in cases where internal-fn.def defines
+- such an internal function.
+-
+- Note that the new code_helper cannot necessarily be used in place of
+- the original code_helper. For example, the new code_helper might be
+- an internal function that the target does not support. */
+-
+-code_helper
+-canonicalize_code (code_helper code, tree type)
+-{
+- if (code.is_fn_code ())
+- return associated_internal_fn (combined_fn (code), type);
+- return code;
+-}
+-
+-/* Return true if CODE is a binary operation and if CODE is commutative when
+- operating on type TYPE. */
+-
+-bool
+-commutative_binary_op_p (code_helper code, tree type)
+-{
+- if (code.is_tree_code ())
+- return commutative_tree_code (tree_code (code));
+- auto cfn = combined_fn (code);
+- return commutative_binary_fn_p (associated_internal_fn (cfn, type));
+-}
+-
+-/* Return true if CODE represents a ternary operation and if the first two
+- operands are commutative when CODE is operating on TYPE. */
+-
+-bool
+-commutative_ternary_op_p (code_helper code, tree type)
+-{
+- if (code.is_tree_code ())
+- return commutative_ternary_tree_code (tree_code (code));
+- auto cfn = combined_fn (code);
+- return commutative_ternary_fn_p (associated_internal_fn (cfn, type));
+-}
+-
+-/* If CODE is commutative in two consecutive operands, return the
+- index of the first, otherwise return -1. */
+-
+-int
+-first_commutative_argument (code_helper code, tree type)
+-{
+- if (code.is_tree_code ())
+- {
+- auto tcode = tree_code (code);
+- if (commutative_tree_code (tcode)
+- || commutative_ternary_tree_code (tcode))
+- return 0;
+- return -1;
+- }
+- auto cfn = combined_fn (code);
+- return first_commutative_argument (associated_internal_fn (cfn, type));
+-}
+-
+-/* Return true if CODE is a binary operation that is associative when
+- operating on type TYPE. */
+-
+-bool
+-associative_binary_op_p (code_helper code, tree type)
+-{
+- if (code.is_tree_code ())
+- return associative_tree_code (tree_code (code));
+- auto cfn = combined_fn (code);
+- return associative_binary_fn_p (associated_internal_fn (cfn, type));
+-}
+-
+-/* Return true if the target directly supports operation CODE on type TYPE.
+- QUERY_TYPE acts as for optab_for_tree_code. */
+-
+-bool
+-directly_supported_p (code_helper code, tree type, optab_subtype query_type)
+-{
+- if (code.is_tree_code ())
+- {
+- direct_optab optab = optab_for_tree_code (tree_code (code), type,
+- query_type);
+- return (optab != unknown_optab
+- && optab_handler (optab, TYPE_MODE (type)) != CODE_FOR_nothing);
+- }
+- gcc_assert (query_type == optab_default
+- || (query_type == optab_vector && VECTOR_TYPE_P (type))
+- || (query_type == optab_scalar && !VECTOR_TYPE_P (type)));
+- internal_fn ifn = associated_internal_fn (combined_fn (code), type);
+- return (direct_internal_fn_p (ifn)
+- && direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED));
+-}
+-
+-/* A wrapper around the internal-fn.cc versions of get_conditional_internal_fn
+- for a code_helper CODE operating on type TYPE. */
+-
+-internal_fn
+-get_conditional_internal_fn (code_helper code, tree type)
+-{
+- if (code.is_tree_code ())
+- return get_conditional_internal_fn (tree_code (code));
+- auto cfn = combined_fn (code);
+- return get_conditional_internal_fn (associated_internal_fn (cfn, type));
+-}
+--
+2.44.0
+
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109927#c21
+
+From daac5d2f67656dcf8cc2bbff1c6eaa34f3fb55b9 Mon Sep 17 00:00:00 2001
+From: Tamar Christina <tamar.christina@arm.com>
+Date: Fri, 5 May 2023 13:38:50 +0100
+Subject: [PATCH 05/15] match.pd: automatically partition *-match.cc files.
+
+Following on from Richi's RFC[1] this is another attempt to split up match.pd
+into multiple gimple-match and generic-match files. This version is fully
+automated and requires no human intervention.
+
+First things first, some perf numbers. The following shows the effect of the
+patch on my desktop doing parallel compilation of gimple-match:
+
++--------+------------------+--------+------------------+
+| splits | rel. improvement | splits | rel. improvement |
++--------+------------------+--------+------------------+
+| 1 | 0.00% | 33 | 91.03% |
+| 2 | 71.77% | 34 | 84.02% |
+| 3 | 100.71% | 35 | 83.42% |
+| 4 | 143.08% | 36 | 78.80% |
+| 5 | 176.18% | 37 | 74.06% |
+| 6 | 174.40% | 38 | 55.76% |
+| 7 | 176.62% | 39 | 66.90% |
+| 8 | 168.35% | 40 | 18.25% |
+| 9 | 189.80% | 41 | 16.55% |
+| 10 | 171.77% | 42 | 47.02% |
+| 11 | 152.82% | 43 | 15.29% |
+| 12 | 112.20% | 44 | 21.63% |
+| 13 | 158.57% | 45 | 41.53% |
+| 14 | 158.57% | 46 | 21.98% |
+| 15 | 152.07% | 47 | -42.74% |
+| 16 | 151.70% | 48 | -32.62% |
+| 17 | 131.52% | 49 | 11.81% |
+| 18 | 133.11% | 50 | 34.07% |
+| 19 | 137.33% | 51 | 2.71% |
+| 20 | 103.83% | 52 | -22.23% |
+| 21 | 132.47% | 53 | 32.30% |
+| 22 | 116.52% | 54 | 21.45% |
+| 23 | 112.73% | 55 | 40.02% |
+| 24 | 111.94% | 56 | 42.83% |
+| 25 | 112.73% | 57 | -9.98% |
+| 26 | 104.07% | 58 | 18.01% |
+| 27 | 113.27% | 59 | -4.91% |
+| 28 | 96.77% | 60 | 22.94% |
+| 29 | 93.42% | 61 | -3.73% |
+| 30 | 87.67% | 62 | -27.43% |
+| 31 | 89.54% | 63 | -1.05% |
+| 32 | 84.42% | 64 | -5.44% |
++--------+------------------+--------+------------------+
+
+As can be seen there seems to be a point of diminishing returns in doing splits.
+This comes from the fact that these match files consume a sizeable amount of
+headers. At a certain point the parsing overhead of the headers dominate and
+you start losing in gains.
+
+As such from this I've made the default 10 splits per file to allow for some
+room for growth in the future without needing changes to the split amount.
+Since 5-10 show roughly the same gains it means we can afford to double the
+file sizes before we need to up the split amount. This can be controlled
+by the configure parameter --with-matchpd-partitions=.
+
+At 10 splits the sizes of the files are:
+
+ 1.2M gimple-match-1.cc
+ 490K gimple-match-2.cc
+ 459K gimple-match-3.cc
+ 462K gimple-match-4.cc
+ 466K gimple-match-5.cc
+ 690K gimple-match-6.cc
+ 517K gimple-match-7.cc
+ 693K gimple-match-8.cc
+1011K gimple-match-9.cc
+ 490K gimple-match-10.cc
+ 210K gimple-match-auto.h
+
+The reason gimple-match-1.cc is so large is because it got allocated a very
+large function: gimple_simplify_NE_EXPR.
+
+Because of these sporadically large functions the allocation to a split happens
+based on the amount of data already written to a split instead of just a simple
+round robin allocation (though the patch supports that too.). This means that
+once gimple_simplify_NE_EXPR is allocated to gimple-match-1.cc nothing uses it
+again until the rest of the files catch up.
+
+To support this split a new header file *-match-auto.h is generated to allow
+the individual files to compile separately.
+
+Lastly for the auto generated files I use pragmas to silence the unused
+predicate warnings instead of the previous Makefile way because I couldn't find
+a way to set them without knowing the number of split files beforehand.
+
+Finally with this change, bootstrap time has dropped 8 minutes on AArch64.
+
+[1] https://gcc.gnu.org/legacy-ml/gcc-patches/2018-04/msg01125.html
+
+gcc/ChangeLog:
+
+ PR bootstrap/84402
+ * genmatch.cc (emit_func, SIZED_BASED_CHUNKS, get_out_file): New.
+ (decision_tree::gen): Accept list of files instead of single and update
+ to write function definition to header and main file.
+ (write_predicate): Likewise.
+ (write_header): Emit pragmas and new includes.
+ (main): Create file buffers and cleanup.
+ (showUsage, write_header_includes): New.
+
+(cherry picked from commit 703417a030b3d80f55ba1402adc3f1692d3631e5)
+---
+ gcc/genmatch.cc | 226 ++++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 190 insertions(+), 36 deletions(-)
+
+diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc
+index 665d7e2106ff..f80e4b972288 100644
+--- a/gcc/genmatch.cc
++++ b/gcc/genmatch.cc
+@@ -183,6 +183,33 @@ fprintf_indent (FILE *f, unsigned int indent, const char *format, ...)
+ va_end (ap);
+ }
+
++/* Like fprintf, but print to two files, one header one C implementation. */
++FILE *header_file = NULL;
++
++static void
++#if GCC_VERSION >= 4001
++__attribute__((format (printf, 4, 5)))
++#endif
++emit_func (FILE *f, bool open, bool close, const char *format, ...)
++{
++ va_list ap1, ap2;
++ if (header_file != NULL)
++ {
++ if (open)
++ fprintf (header_file, "extern ");
++ va_start (ap2, format);
++ vfprintf (header_file, format, ap2);
++ va_end (ap2);
++ if (close)
++ fprintf (header_file, ";\n");
++ }
++
++ va_start (ap1, format);
++ vfprintf (f, format, ap1);
++ va_end (ap1);
++ fputc ('\n', f);
++}
++
+ static void
+ output_line_directive (FILE *f, location_t location,
+ bool dumpfile = false, bool fnargs = false)
+@@ -217,6 +244,37 @@ output_line_directive (FILE *f, location_t location,
+ fprintf (f, "/* #line %d \"%s\" */\n", loc.line, loc.file);
+ }
+
++/* Find the file to write into next. We try to evenly distribute the contents
++ over the different files. */
++
++#define SIZED_BASED_CHUNKS 1
++
++int current_file = 0;
++FILE *get_out_file (vec <FILE *> &parts)
++{
++#ifdef SIZED_BASED_CHUNKS
++ if (parts.length () == 1)
++ return parts[0];
++
++ FILE *f = NULL;
++ long min = 0;
++ /* We've started writing all the files at pos 0, so ftell is equivalent
++ to the size and should be much faster. */
++ for (unsigned i = 0; i < parts.length (); i++)
++ {
++ long res = ftell (parts[i]);
++ if (!f || res < min)
++ {
++ min = res;
++ f = parts[i];
++ }
++ }
++ return f;
++#else
++ return parts[current_file++ % parts.length ()];
++#endif
++}
++
+
+ /* Pull in tree codes and builtin function codes from their
+ definition files. */
+@@ -1732,7 +1790,7 @@ public:
+ dt_node *root;
+
+ void insert (class simplify *, unsigned);
+- void gen (FILE *f, bool gimple);
++ void gen (vec <FILE *> &f, bool gimple);
+ void print (FILE *f = stderr);
+
+ decision_tree () { root = new dt_node (dt_node::DT_NODE, NULL); }
+@@ -3832,7 +3890,7 @@ sinfo_hashmap_traits::equal_keys (const key_type &v,
+ tree. */
+
+ void
+-decision_tree::gen (FILE *f, bool gimple)
++decision_tree::gen (vec <FILE *> &files, bool gimple)
+ {
+ sinfo_map_t si;
+
+@@ -3861,11 +3919,14 @@ decision_tree::gen (FILE *f, bool gimple)
+ output_line_directive (stderr, s->s->s->result->location);
+ }
+
++ /* Cycle the file buffers. */
++ FILE *f = get_out_file (files);
++
+ /* Generate a split out function with the leaf transform code. */
+ s->fname = xasprintf ("%s_simplify_%u", gimple ? "gimple" : "generic",
+ fcnt++);
+ if (gimple)
+- fprintf (f, "\nstatic bool\n"
++ emit_func (f, true, false, "\nbool\n"
+ "%s (gimple_match_op *res_op, gimple_seq *seq,\n"
+ " tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
+ " const tree ARG_UNUSED (type), tree *ARG_UNUSED "
+@@ -3873,27 +3934,28 @@ decision_tree::gen (FILE *f, bool gimple)
+ s->fname);
+ else
+ {
+- fprintf (f, "\nstatic tree\n"
++ emit_func (f, true, false, "\ntree\n"
+ "%s (location_t ARG_UNUSED (loc), const tree ARG_UNUSED (type),\n",
+ (*iter).second->fname);
+ for (unsigned i = 0;
+ i < as_a <expr *>(s->s->s->match)->ops.length (); ++i)
+- fprintf (f, " tree ARG_UNUSED (_p%d),", i);
+- fprintf (f, " tree *captures\n");
++ emit_func (f, false, false, " tree ARG_UNUSED (_p%d),", i);
++ emit_func (f, false, false, " tree *captures\n");
+ }
+ for (unsigned i = 0; i < s->s->s->for_subst_vec.length (); ++i)
+ {
+ if (! s->s->s->for_subst_vec[i].first->used)
+ continue;
+ if (is_a <operator_id *> (s->s->s->for_subst_vec[i].second))
+- fprintf (f, ", const enum tree_code ARG_UNUSED (%s)",
++ emit_func (f, false, false, ", const enum tree_code ARG_UNUSED (%s)",
+ s->s->s->for_subst_vec[i].first->id);
+ else if (is_a <fn_id *> (s->s->s->for_subst_vec[i].second))
+- fprintf (f, ", const combined_fn ARG_UNUSED (%s)",
++ emit_func (f, false, false, ", const combined_fn ARG_UNUSED (%s)",
+ s->s->s->for_subst_vec[i].first->id);
+ }
+
+- fprintf (f, ")\n{\n");
++ emit_func (f, false, true, ")");
++ fprintf (f, "{\n");
+ fprintf_indent (f, 2, "const bool debug_dump = "
+ "dump_file && (dump_flags & TDF_FOLDING);\n");
+ s->s->gen_1 (f, 2, gimple, s->s->s->result);
+@@ -3923,8 +3985,12 @@ decision_tree::gen (FILE *f, bool gimple)
+ && e->operation->kind != id_base::CODE))
+ continue;
+
++
++ /* Cycle the file buffers. */
++ FILE *f = get_out_file (files);
++
+ if (gimple)
+- fprintf (f, "\nstatic bool\n"
++ emit_func (f, true, false,"\nbool\n"
+ "gimple_simplify_%s (gimple_match_op *res_op,"
+ " gimple_seq *seq,\n"
+ " tree (*valueize)(tree) "
+@@ -3933,13 +3999,13 @@ decision_tree::gen (FILE *f, bool gimple)
+ "ARG_UNUSED (type)\n",
+ e->operation->id);
+ else
+- fprintf (f, "\nstatic tree\n"
++ emit_func (f, true, false, "\ntree\n"
+ "generic_simplify_%s (location_t ARG_UNUSED (loc), enum "
+ "tree_code ARG_UNUSED (code), const tree ARG_UNUSED (type)",
+ e->operation->id);
+ for (unsigned i = 0; i < n; ++i)
+- fprintf (f, ", tree _p%d", i);
+- fprintf (f, ")\n");
++ emit_func (f, false, false,", tree _p%d", i);
++ emit_func (f, false, true, ")");
+ fprintf (f, "{\n");
+ fprintf_indent (f, 2, "const bool debug_dump = "
+ "dump_file && (dump_flags & TDF_FOLDING);\n");
+@@ -3956,18 +4022,22 @@ decision_tree::gen (FILE *f, bool gimple)
+ with compiler warnings, by generating a simple stub. */
+ if (! has_kids_p)
+ {
++
++ /* Cycle the file buffers. */
++ FILE *f = get_out_file (files);
++
+ if (gimple)
+- fprintf (f, "\nbool\n"
++ emit_func (f, true, false, "\nbool\n"
+ "gimple_simplify (gimple_match_op*, gimple_seq*,\n"
+ " tree (*)(tree), code_helper,\n"
+ " const tree");
+ else
+- fprintf (f, "\ntree\n"
++ emit_func (f, true, false,"\ntree\n"
+ "generic_simplify (location_t, enum tree_code,\n"
+ " const tree");
+ for (unsigned i = 0; i < n; ++i)
+- fprintf (f, ", tree");
+- fprintf (f, ")\n");
++ emit_func (f, false, false, ", tree");
++ emit_func (f, false, true, ")");
+ fprintf (f, "{\n");
+ if (gimple)
+ fprintf (f, " return false;\n");
+@@ -3977,20 +4047,24 @@ decision_tree::gen (FILE *f, bool gimple)
+ continue;
+ }
+
++
++ /* Cycle the file buffers. */
++ FILE *f = get_out_file (files);
++
+ /* Then generate the main entry with the outermost switch and
+ tail-calls to the split-out functions. */
+ if (gimple)
+- fprintf (f, "\nbool\n"
++ emit_func (f, true, false, "\nbool\n"
+ "gimple_simplify (gimple_match_op *res_op, gimple_seq *seq,\n"
+ " tree (*valueize)(tree) ATTRIBUTE_UNUSED,\n"
+ " code_helper code, const tree type");
+ else
+- fprintf (f, "\ntree\n"
++ emit_func (f, true, false, "\ntree\n"
+ "generic_simplify (location_t loc, enum tree_code code, "
+ "const tree type ATTRIBUTE_UNUSED");
+ for (unsigned i = 0; i < n; ++i)
+- fprintf (f, ", tree _p%d", i);
+- fprintf (f, ")\n");
++ emit_func (f, false, false, ", tree _p%d", i);
++ emit_func (f, false, true, ")");
+ fprintf (f, "{\n");
+
+ if (gimple)
+@@ -4045,11 +4119,11 @@ decision_tree::gen (FILE *f, bool gimple)
+ void
+ write_predicate (FILE *f, predicate_id *p, decision_tree &dt, bool gimple)
+ {
+- fprintf (f, "\nbool\n"
+- "%s%s (tree t%s%s)\n"
+- "{\n", gimple ? "gimple_" : "tree_", p->id,
+- p->nargs > 0 ? ", tree *res_ops" : "",
+- gimple ? ", tree (*valueize)(tree) ATTRIBUTE_UNUSED" : "");
++ emit_func (f, true, true, "\nbool\n%s%s (tree t%s%s)",
++ gimple ? "gimple_" : "tree_", p->id,
++ p->nargs > 0 ? ", tree *res_ops" : "",
++ gimple ? ", tree (*valueize)(tree) ATTRIBUTE_UNUSED" : "");
++ fprintf (f, "{\n");
+ /* Conveniently make 'type' available. */
+ fprintf_indent (f, 2, "const tree type = TREE_TYPE (t);\n");
+ fprintf_indent (f, 2, "const bool debug_dump = "
+@@ -4070,9 +4144,13 @@ write_header (FILE *f, const char *head)
+ {
+ fprintf (f, "/* Generated automatically by the program `genmatch' from\n");
+ fprintf (f, " a IL pattern matching and simplification description. */\n");
++ fprintf (f, "#pragma GCC diagnostic push\n");
++ fprintf (f, "#pragma GCC diagnostic ignored \"-Wunused-variable\"\n");
++ fprintf (f, "#pragma GCC diagnostic ignored \"-Wunused-function\"\n");
+
+ /* Include the header instead of writing it awkwardly quoted here. */
+- fprintf (f, "\n#include \"%s\"\n", head);
++ if (head)
++ fprintf (f, "\n#include \"%s\"\n", head);
+ }
+
+
+@@ -5213,6 +5291,30 @@ round_alloc_size (size_t s)
+ }
+
+
++/* Construct and display the help menu. */
++
++static void
++showUsage ()
++{
++ fprintf (stderr, "Usage: genmatch [--gimple] [--generic] "
++ "[--header=<filename>] [--include=<filename>] [-v[v]] input "
++ "[<outputfile>...]\n");
++ fprintf (stderr, "\nWhen more then one outputfile is specified --header "
++ "is required.\n");
++}
++
++/* Write out the correct include to the match-head fle containing the helper
++ files. */
++
++static void
++write_header_includes (bool gimple, FILE *header_file)
++{
++ if (gimple)
++ fprintf (header_file, "#include \"gimple-match-head.cc\"\n");
++ else
++ fprintf (header_file, "#include \"generic-match-head.cc\"\n");
++}
++
+ /* The genmatch generator program. It reads from a pattern description
+ and outputs GIMPLE or GENERIC IL matching and simplification routines. */
+
+@@ -5227,25 +5329,44 @@ main (int argc, char **argv)
+ return 1;
+
+ bool gimple = true;
+- char *input = argv[argc-1];
+- for (int i = 1; i < argc - 1; ++i)
++ char *s_header_file = NULL;
++ char *s_include_file = NULL;
++ auto_vec <char *> files;
++ char *input = NULL;
++ int last_file = argc - 1;
++ for (int i = argc - 1; i >= 1; --i)
+ {
+ if (strcmp (argv[i], "--gimple") == 0)
+ gimple = true;
+ else if (strcmp (argv[i], "--generic") == 0)
+ gimple = false;
++ else if (strncmp (argv[i], "--header=", 9) == 0)
++ s_header_file = &argv[i][9];
++ else if (strncmp (argv[i], "--include=", 10) == 0)
++ s_include_file = &argv[i][10];
+ else if (strcmp (argv[i], "-v") == 0)
+ verbose = 1;
+ else if (strcmp (argv[i], "-vv") == 0)
+ verbose = 2;
++ else if (strncmp (argv[i], "--", 2) != 0 && last_file-- == i)
++ files.safe_push (argv[i]);
+ else
+ {
+- fprintf (stderr, "Usage: genmatch "
+- "[--gimple] [--generic] [-v[v]] input\n");
++ showUsage ();
+ return 1;
+ }
+ }
+
++ /* Validate if the combinations are valid. */
++ if ((files.length () > 1 && !s_header_file) || files.is_empty ())
++ showUsage ();
++
++ if (!s_include_file)
++ s_include_file = s_header_file;
++
++ /* Input file is the last in the reverse list. */
++ input = files.pop ();
++
+ line_table = XCNEW (class line_maps);
+ linemap_init (line_table, 0);
+ line_table->reallocator = xrealloc;
+@@ -5292,10 +5413,28 @@ main (int argc, char **argv)
+ /* Parse ahead! */
+ parser p (r, gimple);
+
+- if (gimple)
+- write_header (stdout, "gimple-match-head.cc");
++ /* Create file buffers. */
++ int n_parts = files.is_empty () ? 1 : files.length ();
++ auto_vec <FILE *> parts (n_parts);
++ if (files.is_empty ())
++ {
++ parts.quick_push (stdout);
++ write_header (stdout, s_include_file);
++ write_header_includes (gimple, stdout);
++ }
+ else
+- write_header (stdout, "generic-match-head.cc");
++ {
++ for (char *s_file : files)
++ {
++ parts.quick_push (fopen (s_file, "w"));
++ write_header (parts.last (), s_include_file);
++ }
++
++ header_file = fopen (s_header_file, "w");
++ fprintf (header_file, "#ifndef GCC_GIMPLE_MATCH_AUTO_H\n"
++ "#define GCC_GIMPLE_MATCH_AUTO_H\n");
++ write_header_includes (gimple, header_file);
++ }
+
+ /* Go over all predicates defined with patterns and perform
+ lowering and code generation. */
+@@ -5315,7 +5454,10 @@ main (int argc, char **argv)
+ if (verbose == 2)
+ dt.print (stderr);
+
+- write_predicate (stdout, pred, dt, gimple);
++ /* Cycle the file buffers. */
++ FILE *f = get_out_file (parts);
++
++ write_predicate (f, pred, dt, gimple);
+ }
+
+ /* Lower the main simplifiers and generate code for them. */
+@@ -5332,7 +5474,19 @@ main (int argc, char **argv)
+ if (verbose == 2)
+ dt.print (stderr);
+
+- dt.gen (stdout, gimple);
++ dt.gen (parts, gimple);
++
++ for (FILE *f : parts)
++ {
++ fprintf (f, "#pragma GCC diagnostic pop\n");
++ fclose (f);
++ }
++
++ if (header_file)
++ {
++ fprintf (header_file, "#endif /* GCC_GIMPLE_MATCH_AUTO_H. */\n");
++ fclose (header_file);
++ }
+
+ /* Finalize. */
+ cpp_finish (r, NULL);
+--
+2.44.0
+
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109927#c21
+
+From dcfebe060ee266f364bb60f1cdf0cec58818c4f7 Mon Sep 17 00:00:00 2001
+From: Tamar Christina <tamar.christina@arm.com>
+Date: Fri, 5 May 2023 13:42:17 +0100
+Subject: [PATCH 06/15] match.pd: Use splits in makefile and make configurable.
+
+This updates the build system to split up match.pd files into chunks of 10.
+This also introduces a new flag --with-matchpd-partitions which can be used to
+change the number of partitions.
+
+For the analysis of why 10 please look at the previous patch in the series.
+
+gcc/ChangeLog:
+
+ PR bootstrap/84402
+ * Makefile.in (NUM_MATCH_SPLITS, MATCH_SPLITS_SEQ,
+ GIMPLE_MATCH_PD_SEQ_SRC, GIMPLE_MATCH_PD_SEQ_O,
+ GENERIC_MATCH_PD_SEQ_SRC, GENERIC_MATCH_PD_SEQ_O): New.
+ (OBJS, MOSTLYCLEANFILES, .PRECIOUS): Use them.
+ (s-match): Split into s-generic-match and s-gimple-match.
+ * configure.ac (with-matchpd-partitions,
+ DEFAULT_MATCHPD_PARTITIONS): New.
+ * configure: Regenerate.
+
+(cherry picked from commit 0a85544e1aaeca41133ecfc438cda913dbc0f122)
+---
+ gcc/Makefile.in | 67 +++++++++++++++++++++++++++++++++---------------
+ gcc/config.in | 6 +++++
+ gcc/configure | 29 +++++++++++++++++++--
+ gcc/configure.ac | 15 +++++++++++
+ 4 files changed, 95 insertions(+), 22 deletions(-)
+
+diff --git a/gcc/Makefile.in b/gcc/Makefile.in
+index 406856acde1c..f0c34d00ecbc 100644
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -214,6 +214,14 @@ rtl-ssa-warn = $(STRICT_WARN)
+ GCC_WARN_CFLAGS = $(LOOSE_WARN) $(C_LOOSE_WARN) $($(@D)-warn) $(if $(filter-out $(STRICT_WARN),$($(@D)-warn)),,$(C_STRICT_WARN)) $(NOCOMMON_FLAG) $($@-warn)
+ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn)
+
++# The number of splits to be made for the match.pd files.
++NUM_MATCH_SPLITS = @DEFAULT_MATCHPD_PARTITIONS@
++MATCH_SPLITS_SEQ = $(shell seq 1 $(NUM_MATCH_SPLITS))
++GIMPLE_MATCH_PD_SEQ_SRC = $(patsubst %, gimple-match-%.cc, $(MATCH_SPLITS_SEQ))
++GIMPLE_MATCH_PD_SEQ_O = $(patsubst %, gimple-match-%.o, $(MATCH_SPLITS_SEQ))
++GENERIC_MATCH_PD_SEQ_SRC = $(patsubst %, generic-match-%.cc, $(MATCH_SPLITS_SEQ))
++GENERIC_MATCH_PD_SEQ_O = $(patsubst %, generic-match-%.o, $(MATCH_SPLITS_SEQ))
++
+ # These files are to have specific diagnostics suppressed, or are not to
+ # be subject to -Werror:
+ # flex output may yield harmless "no previous prototype" warnings
+@@ -222,9 +230,8 @@ gengtype-lex.o-warn = -Wno-error
+ libgcov-util.o-warn = -Wno-error
+ libgcov-driver-tool.o-warn = -Wno-error
+ libgcov-merge-tool.o-warn = -Wno-error
+-gimple-match.o-warn = -Wno-unused
++gimple-match-head.o-warn = -Wno-unused
+ gimple-match-exports.o-warn = -Wno-unused
+-generic-match.o-warn = -Wno-unused
+ dfp.o-warn = -Wno-strict-aliasing
+
+ # All warnings have to be shut off in stage1 if the compiler used then
+@@ -1312,9 +1319,9 @@ ANALYZER_OBJS = \
+ # will build them sooner, because they are large and otherwise tend to be
+ # the last objects to finish building.
+ OBJS = \
+- gimple-match.o \
++ $(GIMPLE_MATCH_PD_SEQ_O) \
+ gimple-match-exports.o \
+- generic-match.o \
++ $(GENERIC_MATCH_PD_SEQ_O) \
+ insn-attrtab.o \
+ insn-automata.o \
+ insn-dfatab.o \
+@@ -1807,7 +1814,8 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
+ insn-output.cc insn-recog.cc insn-emit.cc insn-extract.cc insn-peep.cc \
+ insn-attr.h insn-attr-common.h insn-attrtab.cc insn-dfatab.cc \
+ insn-latencytab.cc insn-opinit.cc insn-opinit.h insn-preds.cc insn-constants.h \
+- tm-preds.h tm-constrs.h checksum-options gimple-match.cc generic-match.cc \
++ tm-preds.h tm-constrs.h checksum-options $(GIMPLE_MATCH_PD_SEQ_SRC) \
++ $(GENERIC_MATCH_PD_SEQ_SRC) gimple-match-auto.h generic-match-auto.h \
+ tree-check.h min-insn-modes.cc insn-modes.cc insn-modes.h insn-modes-inline.h \
+ genrtl.h gt-*.h gtype-*.h gtype-desc.cc gtyp-input.list \
+ case-cfn-macros.h cfn-operators.pd \
+@@ -2422,7 +2430,8 @@ $(common_out_object_file): $(common_out_file)
+ .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \
+ insn-emit.cc insn-recog.cc insn-extract.cc insn-output.cc insn-peep.cc \
+ insn-attr.h insn-attr-common.h insn-attrtab.cc insn-dfatab.cc \
+- insn-latencytab.cc insn-preds.cc gimple-match.cc generic-match.cc \
++ insn-latencytab.cc insn-preds.cc $(GIMPLE_MATCH_PD_SEQ_SRC) \
++ $(GENERIC_MATCH_PD_SEQ_SRC) gimple-match-auto.h generic-match-auto.h \
+ insn-target-def.h
+
+ # Dependencies for the md file. The first time through, we just assume
+@@ -2665,19 +2674,36 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
+ false; \
+ fi
+
+-gimple-match.cc: s-match gimple-match-head.cc gimple-match-exports.cc ; @true
+-generic-match.cc: s-match generic-match-head.cc ; @true
+-
+-s-match: build/genmatch$(build_exeext) $(srcdir)/match.pd cfn-operators.pd
+- $(RUN_GEN) build/genmatch$(build_exeext) --gimple $(srcdir)/match.pd \
+- > tmp-gimple-match.cc
+- $(RUN_GEN) build/genmatch$(build_exeext) --generic $(srcdir)/match.pd \
+- > tmp-generic-match.cc
+- $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match.cc \
+- gimple-match.cc
+- $(SHELL) $(srcdir)/../move-if-change tmp-generic-match.cc \
+- generic-match.cc
+- $(STAMP) s-match
++$(GIMPLE_MATCH_PD_SEQ_SRC): s-gimple-match gimple-match-head.cc \
++ gimple-match-exports.cc; @true
++gimple-match-auto.h: s-gimple-match gimple-match-head.cc \
++ gimple-match-exports.cc; @true
++$(GENERIC_MATCH_PD_SEQ_SRC): s-generic-match generic-match-head.cc; @true
++generic-match-auto.h: s-generic-match generic-match-head.cc; @true
++
++s-gimple-match: build/genmatch$(build_exeext) \
++ $(srcdir)/match.pd cfn-operators.pd
++ $(RUN_GEN) build/genmatch$(build_exeext) --gimple \
++ --header=tmp-gimple-match-auto.h --include=gimple-match-auto.h \
++ $(srcdir)/match.pd $(patsubst %, tmp-%, $(GIMPLE_MATCH_PD_SEQ_SRC))
++ $(foreach id, $(MATCH_SPLITS_SEQ), \
++ $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match-$(id).cc \
++ gimple-match-$(id).cc;)
++ $(SHELL) $(srcdir)/../move-if-change tmp-gimple-match-auto.h \
++ gimple-match-auto.h
++ $(STAMP) s-gimple-match
++
++s-generic-match: build/genmatch$(build_exeext) \
++ $(srcdir)/match.pd cfn-operators.pd
++ $(RUN_GEN) build/genmatch$(build_exeext) --generic \
++ --header=tmp-generic-match-auto.h --include=generic-match-auto.h \
++ $(srcdir)/match.pd $(patsubst %, tmp-%, $(GENERIC_MATCH_PD_SEQ_SRC))
++ $(foreach id, $(MATCH_SPLITS_SEQ), \
++ $(SHELL) $(srcdir)/../move-if-change tmp-generic-match-$(id).cc \
++ generic-match-$(id).cc;)
++ $(SHELL) $(srcdir)/../move-if-change tmp-generic-match-auto.h \
++ generic-match-auto.h
++ $(STAMP) s-generic-match
+
+ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
+ $(host_xm_file_list) \
+@@ -2812,7 +2838,8 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_H) multilib.h \
+ $(ALL_GTFILES_H) gtype-desc.cc gtype-desc.h version.h \
+ options.h target-hooks-def.h insn-opinit.h \
+ common/common-target-hooks-def.h pass-instances.def \
+- gimple-match.cc generic-match.cc \
++ $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \
++ gimple-match-auto.h generic-match-auto.h \
+ c-family/c-target-hooks-def.h d/d-target-hooks-def.h \
+ case-cfn-macros.h \
+ cfn-operators.pd omp-device-properties.h
+diff --git a/gcc/config.in b/gcc/config.in
+index 5281a12a707c..ea60c5b11fc5 100644
+--- a/gcc/config.in
++++ b/gcc/config.in
+@@ -67,6 +67,12 @@
+ #endif
+
+
++/* Define to larger than one set the number of match.pd partitions to make. */
++#ifndef USED_FOR_TARGET
++#undef DEFAULT_MATCHPD_PARTITIONS
++#endif
++
++
+ /* Define to larger than zero set the default stack clash protector size. */
+ #ifndef USED_FOR_TARGET
+ #undef DEFAULT_STK_CLASH_GUARD_SIZE
+diff --git a/gcc/configure b/gcc/configure
+index ade0af23e8cc..542d100c2b73 100755
+--- a/gcc/configure
++++ b/gcc/configure
+@@ -838,6 +838,7 @@ enable_gcov
+ enable_shared
+ enable_fixed_point
+ enable_decimal_float
++DEFAULT_MATCHPD_PARTITIONS
+ with_float
+ with_cpu
+ enable_multiarch
+@@ -965,6 +966,7 @@ enable_valgrind_annotations
+ enable_multilib
+ enable_multiarch
+ with_stack_clash_protection_guard_size
++with_matchpd_partitions
+ enable___cxa_atexit
+ enable_decimal_float
+ enable_fixed_point
+@@ -1832,6 +1834,9 @@ Optional Packages:
+ --with-stack-clash-protection-guard-size=size
+ Set the default stack clash protection guard size
+ for specific targets as a power of two in bytes.
++ --with-matchpd-partitions=num
++ Set the number of partitions to make for gimple and
++ generic when splitting match.pd. [default=10]
+ --with-dwarf2 force the default debug format to be DWARF 2 (or
+ later)
+ --with-specs=SPECS add SPECS to driver command-line processing
+@@ -7918,6 +7923,26 @@ cat >>confdefs.h <<_ACEOF
+ _ACEOF
+
+
++# Specify the number of splits of match.pd to generate.
++
++# Check whether --with-matchpd-partitions was given.
++if test "${with_matchpd_partitions+set}" = set; then :
++ withval=$with_matchpd_partitions; DEFAULT_MATCHPD_PARTITIONS="$with_matchpd_partitions"
++else
++ DEFAULT_MATCHPD_PARTITIONS=10
++fi
++
++if (test $DEFAULT_MATCHPD_PARTITIONS -lt 1); then
++ as_fn_error $? "Invalid value $DEFAULT_MATCHPD_PARTITIONS for --with-matchpd-partitions. Cannot be negative." "$LINENO" 5
++fi
++
++
++cat >>confdefs.h <<_ACEOF
++#define DEFAULT_MATCHPD_PARTITIONS $DEFAULT_MATCHPD_PARTITIONS
++_ACEOF
++
++
++
+ # Enable __cxa_atexit for C++.
+ # Check whether --enable-__cxa_atexit was given.
+ if test "${enable___cxa_atexit+set}" = set; then :
+@@ -19871,7 +19896,7 @@ else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+-#line 19874 "configure"
++#line 19899 "configure"
+ #include "confdefs.h"
+
+ #if HAVE_DLFCN_H
+@@ -19977,7 +20002,7 @@ else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+-#line 19980 "configure"
++#line 20005 "configure"
+ #include "confdefs.h"
+
+ #if HAVE_DLFCN_H
+diff --git a/gcc/configure.ac b/gcc/configure.ac
+index bf8ff4d63906..31aa8566a3e7 100644
+--- a/gcc/configure.ac
++++ b/gcc/configure.ac
+@@ -943,6 +943,21 @@ fi
+ AC_DEFINE_UNQUOTED(DEFAULT_STK_CLASH_GUARD_SIZE, $DEFAULT_STK_CLASH_GUARD_SIZE,
+ [Define to larger than zero set the default stack clash protector size.])
+
++# Specify the number of splits of match.pd to generate.
++AC_ARG_WITH(matchpd-partitions,
++[AS_HELP_STRING([--with-matchpd-partitions=num],
++[Set the number of partitions to make for gimple and generic when splitting match.pd. [default=10]])],
++[DEFAULT_MATCHPD_PARTITIONS="$with_matchpd_partitions"], [DEFAULT_MATCHPD_PARTITIONS=10])
++if (test $DEFAULT_MATCHPD_PARTITIONS -lt 1); then
++ AC_MSG_ERROR(m4_normalize([
++ Invalid value $DEFAULT_MATCHPD_PARTITIONS for --with-matchpd-partitions. \
++ Cannot be negative.]))
++fi
++
++AC_DEFINE_UNQUOTED(DEFAULT_MATCHPD_PARTITIONS, $DEFAULT_MATCHPD_PARTITIONS,
++ [Define to larger than one set the number of match.pd partitions to make.])
++AC_SUBST(DEFAULT_MATCHPD_PARTITIONS)
++
+ # Enable __cxa_atexit for C++.
+ AC_ARG_ENABLE(__cxa_atexit,
+ [AS_HELP_STRING([--enable-__cxa_atexit], [enable __cxa_atexit for C++])],
+--
+2.44.0
+
+From 2c1f550db00c7dd9abede5644a3acd915767e0ad Mon Sep 17 00:00:00 2001
+From: Alexander Monakov <amonakov@ispras.ru>
+Date: Fri, 5 May 2023 19:46:25 +0300
+Subject: [PATCH 07/15] Makefile.in: clean up match.pd-related dependencies
+
+Clean up confusing changes from the recent refactoring for
+parallel match.pd build.
+
+gimple-match-head.o is not built. Remove related flags adjustment.
+
+Autogenerated gimple-match-N.o files do not depend on
+gimple-match-exports.cc.
+
+{gimple,generic)-match-auto.h only depend on the prerequisites of the
+corresponding s-{gimple,generic}-match stamp file, not any .cc file.
+
+gcc/ChangeLog:
+
+ * Makefile.in: (gimple-match-head.o-warn): Remove.
+ (GIMPLE_MATCH_PD_SEQ_SRC): Do not depend on
+ gimple-match-exports.cc.
+ (gimple-match-auto.h): Only depend on s-gimple-match.
+ (generic-match-auto.h): Likewise.
+
+(cherry picked from commit 31c70a7daa368767f0f58e0389deb2c69d9e14fd)
+---
+ gcc/Makefile.in | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/gcc/Makefile.in b/gcc/Makefile.in
+index f0c34d00ecbc..fe3af5c8008c 100644
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -230,7 +230,6 @@ gengtype-lex.o-warn = -Wno-error
+ libgcov-util.o-warn = -Wno-error
+ libgcov-driver-tool.o-warn = -Wno-error
+ libgcov-merge-tool.o-warn = -Wno-error
+-gimple-match-head.o-warn = -Wno-unused
+ gimple-match-exports.o-warn = -Wno-unused
+ dfp.o-warn = -Wno-strict-aliasing
+
+@@ -2674,12 +2673,10 @@ s-tm-texi: build/genhooks$(build_exeext) $(srcdir)/doc/tm.texi.in
+ false; \
+ fi
+
+-$(GIMPLE_MATCH_PD_SEQ_SRC): s-gimple-match gimple-match-head.cc \
+- gimple-match-exports.cc; @true
+-gimple-match-auto.h: s-gimple-match gimple-match-head.cc \
+- gimple-match-exports.cc; @true
++$(GIMPLE_MATCH_PD_SEQ_SRC): s-gimple-match gimple-match-head.cc; @true
++gimple-match-auto.h: s-gimple-match; @true
+ $(GENERIC_MATCH_PD_SEQ_SRC): s-generic-match generic-match-head.cc; @true
+-generic-match-auto.h: s-generic-match generic-match-head.cc; @true
++generic-match-auto.h: s-generic-match; @true
+
+ s-gimple-match: build/genmatch$(build_exeext) \
+ $(srcdir)/match.pd cfn-operators.pd
+--
+2.44.0
+
+https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=319aef8d2fde32be5cfed99f321c7f90e33d1f1d
+
+From a18a994030d16f58ebced231e778ec4e06a98abb Mon Sep 17 00:00:00 2001
+From: Jakub Jelinek <jakub@redhat.com>
+Date: Sat, 6 May 2023 02:32:17 +0200
+Subject: [PATCH 08/15] build: Replace seq for portability with GNU Make
+ variant
+
+Some hosts like AIX don't have seq command, this patch replaces it
+with something that uses just GNU make features we've been using
+for this already before for the parallel make check.
+
+2023-05-06 Jakub Jelinek <jakub@redhat.com>
+
+ * Makefile.in (check_p_numbers): Rename to one_to_9999, move
+ earlier with helper variables also renamed.
+ (MATCH_SPLUT_SEQ): Use $(wordlist 1,$(NUM_MATCH_SPLITS),$(one_to_9999))
+ instead of $(shell seq 1 $(NUM_MATCH_SPLITS)).
+ (check_p_subdirs): Use $(one_to_9999) instead of $(check_p_numbers).
+
+(cherry picked from commit 319aef8d2fde32be5cfed99f321c7f90e33d1f1d)
+---
+ gcc/Makefile.in | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/gcc/Makefile.in b/gcc/Makefile.in
+index fe3af5c8008c..975fbb61ea8a 100644
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -214,9 +214,19 @@ rtl-ssa-warn = $(STRICT_WARN)
+ GCC_WARN_CFLAGS = $(LOOSE_WARN) $(C_LOOSE_WARN) $($(@D)-warn) $(if $(filter-out $(STRICT_WARN),$($(@D)-warn)),,$(C_STRICT_WARN)) $(NOCOMMON_FLAG) $($@-warn)
+ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn)
+
++# 1 2 3 ... 9999
++one_to_9999_0:=1 2 3 4 5 6 7 8 9
++one_to_9999_1:=0 $(one_to_9999_0)
++one_to_9999_2:=$(foreach i,$(one_to_9999_0),$(addprefix $(i),$(one_to_9999_1)))
++one_to_9999_3:=$(addprefix 0,$(one_to_9999_1)) $(one_to_9999_2)
++one_to_9999_4:=$(foreach i,$(one_to_9999_0),$(addprefix $(i),$(one_to_9999_3)))
++one_to_9999_5:=$(addprefix 0,$(one_to_9999_3)) $(one_to_9999_4)
++one_to_9999_6:=$(foreach i,$(one_to_9999_0),$(addprefix $(i),$(one_to_9999_5)))
++one_to_9999:=$(one_to_9999_0) $(one_to_9999_2) $(one_to_9999_4) $(one_to_9999_6)
++
+ # The number of splits to be made for the match.pd files.
+ NUM_MATCH_SPLITS = @DEFAULT_MATCHPD_PARTITIONS@
+-MATCH_SPLITS_SEQ = $(shell seq 1 $(NUM_MATCH_SPLITS))
++MATCH_SPLITS_SEQ = $(wordlist 1,$(NUM_MATCH_SPLITS),$(one_to_9999))
+ GIMPLE_MATCH_PD_SEQ_SRC = $(patsubst %, gimple-match-%.cc, $(MATCH_SPLITS_SEQ))
+ GIMPLE_MATCH_PD_SEQ_O = $(patsubst %, gimple-match-%.o, $(MATCH_SPLITS_SEQ))
+ GENERIC_MATCH_PD_SEQ_SRC = $(patsubst %, generic-match-%.cc, $(MATCH_SPLITS_SEQ))
+@@ -4224,18 +4234,10 @@ $(patsubst %,%-subtargets,$(lang_checks)): check-%-subtargets:
+ check_p_tool=$(firstword $(subst _, ,$*))
+ check_p_count=$(check_$(check_p_tool)_parallelize)
+ check_p_subno=$(word 2,$(subst _, ,$*))
+-check_p_numbers0:=1 2 3 4 5 6 7 8 9
+-check_p_numbers1:=0 $(check_p_numbers0)
+-check_p_numbers2:=$(foreach i,$(check_p_numbers0),$(addprefix $(i),$(check_p_numbers1)))
+-check_p_numbers3:=$(addprefix 0,$(check_p_numbers1)) $(check_p_numbers2)
+-check_p_numbers4:=$(foreach i,$(check_p_numbers0),$(addprefix $(i),$(check_p_numbers3)))
+-check_p_numbers5:=$(addprefix 0,$(check_p_numbers3)) $(check_p_numbers4)
+-check_p_numbers6:=$(foreach i,$(check_p_numbers0),$(addprefix $(i),$(check_p_numbers5)))
+-check_p_numbers:=$(check_p_numbers0) $(check_p_numbers2) $(check_p_numbers4) $(check_p_numbers6)
+ check_p_subdir=$(subst _,,$*)
+ check_p_subdirs=$(wordlist 1,$(check_p_count),$(wordlist 1, \
+ $(if $(GCC_TEST_PARALLEL_SLOTS),$(GCC_TEST_PARALLEL_SLOTS),128), \
+- $(check_p_numbers)))
++ $(one_to_9999)))
+
+ # For parallelized check-% targets, this decides whether parallelization
+ # is desirable (if -jN is used). If desirable, recursive make is run with
+--
+2.44.0
+
+https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=bc45e18d433f879a02e369d027829f90f9e85724
+
+From b60091fe7d22e0cac71461dceeb804e37555b5d3 Mon Sep 17 00:00:00 2001
+From: Tamar Christina <tamar.christina@arm.com>
+Date: Mon, 12 Jun 2023 14:06:08 +0100
+Subject: [PATCH 09/15] Remove DEFAULT_MATCHPD_PARTITIONS macro
+
+As Jakub pointed out, DEFAULT_MATCHPD_PARTITIONS
+is now unused and can be removed.
+
+gcc/ChangeLog:
+
+ * config.in: Regenerate.
+ * configure: Regenerate.
+ * configure.ac: Remove DEFAULT_MATCHPD_PARTITIONS.
+
+(cherry picked from commit bc45e18d433f879a02e369d027829f90f9e85724)
+---
+ gcc/config.in | 6 ------
+ gcc/configure | 9 ++-------
+ gcc/configure.ac | 2 --
+ 3 files changed, 2 insertions(+), 15 deletions(-)
+
+diff --git a/gcc/config.in b/gcc/config.in
+index ea60c5b11fc5..5281a12a707c 100644
+--- a/gcc/config.in
++++ b/gcc/config.in
+@@ -67,12 +67,6 @@
+ #endif
+
+
+-/* Define to larger than one set the number of match.pd partitions to make. */
+-#ifndef USED_FOR_TARGET
+-#undef DEFAULT_MATCHPD_PARTITIONS
+-#endif
+-
+-
+ /* Define to larger than zero set the default stack clash protector size. */
+ #ifndef USED_FOR_TARGET
+ #undef DEFAULT_STK_CLASH_GUARD_SIZE
+diff --git a/gcc/configure b/gcc/configure
+index 542d100c2b73..cc8247037569 100755
+--- a/gcc/configure
++++ b/gcc/configure
+@@ -7937,11 +7937,6 @@ if (test $DEFAULT_MATCHPD_PARTITIONS -lt 1); then
+ fi
+
+
+-cat >>confdefs.h <<_ACEOF
+-#define DEFAULT_MATCHPD_PARTITIONS $DEFAULT_MATCHPD_PARTITIONS
+-_ACEOF
+-
+-
+
+ # Enable __cxa_atexit for C++.
+ # Check whether --enable-__cxa_atexit was given.
+@@ -19896,7 +19891,7 @@ else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+-#line 19899 "configure"
++#line 19894 "configure"
+ #include "confdefs.h"
+
+ #if HAVE_DLFCN_H
+@@ -20002,7 +19997,7 @@ else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+-#line 20005 "configure"
++#line 20000 "configure"
+ #include "confdefs.h"
+
+ #if HAVE_DLFCN_H
+diff --git a/gcc/configure.ac b/gcc/configure.ac
+index 31aa8566a3e7..d02ffc22a3a3 100644
+--- a/gcc/configure.ac
++++ b/gcc/configure.ac
+@@ -954,8 +954,6 @@ if (test $DEFAULT_MATCHPD_PARTITIONS -lt 1); then
+ Cannot be negative.]))
+ fi
+
+-AC_DEFINE_UNQUOTED(DEFAULT_MATCHPD_PARTITIONS, $DEFAULT_MATCHPD_PARTITIONS,
+- [Define to larger than one set the number of match.pd partitions to make.])
+ AC_SUBST(DEFAULT_MATCHPD_PARTITIONS)
+
+ # Enable __cxa_atexit for C++.
+--
+2.44.0
+