diff options
author | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2024-05-23 23:40:10 -0500 |
---|---|---|
committer | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2024-08-07 09:57:51 -0500 |
commit | 93cf7fc8b05fe3003b6f16b766622544cdf3830b (patch) | |
tree | 594b1c2e06144b9e0b0dae1310399b5935ddc5ff /system/gcc/match-split.patch | |
parent | d15fa95546e4f4200700750986fb5e249d9bfbe1 (diff) | |
download | packages-93cf7fc8b05fe3003b6f16b766622544cdf3830b.tar.gz packages-93cf7fc8b05fe3003b6f16b766622544cdf3830b.tar.bz2 packages-93cf7fc8b05fe3003b6f16b766622544cdf3830b.tar.xz packages-93cf7fc8b05fe3003b6f16b766622544cdf3830b.zip |
system/gcc: Update to 13.3.0
0012-static-pie and 201-ada were forward-ported by my own paws.
Three digit 0xx underscore patches are from Gentoo. This is also the
source of the insn-split and match-split patches, which significantly
increase performance on build. They are also the source of the new
configure option --with-matchpd-partitions. On systems with very many
cores/threads, a number higher than 32 would probably perform even
better, but 32 should give decent perf on 8+ threads, and runs quite
nicely on the 64-thread Talos II I ran the testbuild on.
202 is from Void. The 300s are originally written by me.
The Ada patch now includes an improvement to use posix_openpt instead
of getpt, which fixes link errors later on.
We also now use STAGE1_CFLAGS and BOOT_CFLAGS to improve build times.
Improvement was clocked from 40m to 32m (-8m, or 20%) on gwyn.
The patch for Go name mangling is needed to build packages that use
reflect2, which includes user/gitlab-runner.
Diffstat (limited to 'system/gcc/match-split.patch')
-rw-r--r-- | system/gcc/match-split.patch | 3583 |
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 + |