[v2,3/3] middle-end: add gimple-isel-match.pd
Commit Message
This commits adds gimple-isel-match.pd which is a match.pd version that only
applies it's rewriting rules at gimple-isel time. The normal match.pd rules
are also later applied at the end of the pass as normal.
The file is currently empty, but I have some patches to add vector comparisons
matching to this and I noticed a few cases already in isel that can be
simplified using the match.pd machinery.
Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.
Ok for master?
Thanks,
Tamar
gcc/ChangeLog:
* Makefile.in: Add entries for gimple-isel-match.pd
* gimple-isel.cc (gimple_isel_simplify): Forward declare.
(pass_gimple_isel::execute): Call it.
* gimple-isel-match.pd: New file.
---
--
Comments
On Thu, 16 Jul 2026, Tamar Christina wrote:
> This commits adds gimple-isel-match.pd which is a match.pd version that only
> applies it's rewriting rules at gimple-isel time. The normal match.pd rules
> are also later applied at the end of the pass as normal.
>
> The file is currently empty, but I have some patches to add vector comparisons
> matching to this and I noticed a few cases already in isel that can be
> simplified using the match.pd machinery.
>
> Bootstrapped Regtested on aarch64-none-linux-gnu,
> arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
> -m32, -m64 and no issues.
>
> Ok for master?
>
> Thanks,
> Tamar
>
> gcc/ChangeLog:
>
> * Makefile.in: Add entries for gimple-isel-match.pd
> * gimple-isel.cc (gimple_isel_simplify): Forward declare.
> (pass_gimple_isel::execute): Call it.
> * gimple-isel-match.pd: New file.
>
> ---
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index fa46ada4980ff8fcbdba696f46e81f59b83dc4b4..09fd733c0b80b5c36546f0c54b6a12cc127003fc 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -228,6 +228,10 @@ 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))
>
> +# The number of splits to be made for the gimple-isel-match.pd files.
> +GIMPLE_ISEL_MATCH_PD_SEQ_SRC = $(patsubst %, gimple-isel-match-%.cc, $(MATCH_SPLITS_SEQ))
> +GIMPLE_ISEL_MATCH_PD_SEQ_O = $(patsubst %, gimple-isel-match-%.o, $(MATCH_SPLITS_SEQ))
> +
I think we can avoid splitting this for now?
> # The number of splits to be made for the insn-emit files.
> NUM_INSNEMIT_SPLITS = @DEFAULT_INSNEMIT_PARTITIONS@
> INSNEMIT_SPLITS_SEQ = $(wordlist 1,$(NUM_INSNEMIT_SPLITS),$(one_to_9999))
> @@ -1401,6 +1405,7 @@ ANALYZER_OBJS = \
> # the last objects to finish building.
> OBJS = \
> $(GIMPLE_MATCH_PD_SEQ_O) \
> + $(GIMPLE_ISEL_MATCH_PD_SEQ_O) \
> gimple-match-exports.o \
> $(GENERIC_MATCH_PD_SEQ_O) \
> insn-attrtab.o \
> @@ -1987,7 +1992,8 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
> 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_PD_SEQ_SRC) \
> - $(GENERIC_MATCH_PD_SEQ_SRC) gimple-match-auto.h generic-match-auto.h \
> + $(GIMPLE_ISEL_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 \
> @@ -2762,6 +2768,7 @@ $(common_out_object_file): $(common_out_file)
> 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_ISEL_MATCH_PD_SEQ_SRC) \
> $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \
> gimple-match-auto.h generic-match-auto.h insn-target-def.h
>
> @@ -3077,6 +3084,23 @@ s-generic-match: build/genmatch$(build_exeext) \
> generic-match-auto.h
> $(STAMP) s-generic-match
>
> +# Add gimple-isel-match.pd
> +$(GIMPLE_ISEL_MATCH_PD_SEQ_SRC): s-gimple-isel-match gimple-match-head.cc; @true
> +gimple-isel-match-auto.h: s-gimple-isel-match; @true
> +
> +s-gimple-isel-match: build/genmatch$(build_exeext) \
> + $(srcdir)/gimple-isel-match.pd cfn-operators.pd
> + $(RUN_GEN) build/genmatch$(build_exeext) --gimple \
> + --header=tmp-gimple-isel-match-auto.h \
> + --include=gimple-isel-match-auto.h --namespace=isel \
> + $(srcdir)/gimple-isel-match.pd $(patsubst %, tmp-%, $(GIMPLE_ISEL_MATCH_PD_SEQ_SRC))
> + $(foreach id, $(MATCH_SPLITS_SEQ), \
> + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-isel-match-$(id).cc \
> + gimple-isel-match-$(id).cc;)
> + $(SHELL) $(srcdir)/../move-if-change tmp-gimple-isel-match-auto.h \
> + gimple-isel-match-auto.h
> + $(STAMP) s-gimple-isel-match
> +
> GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
> $(host_xm_file_list) \
> $(OPTIONS_H_EXTRA) \
> @@ -3216,6 +3240,7 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_JIT_H) $(TM_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_ISEL_MATCH_PD_SEQ_SRC) \
> $(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 \
> diff --git a/gcc/gimple-isel-match.pd b/gcc/gimple-isel-match.pd
> new file mode 100644
> index 0000000000000000000000000000000000000000..9e2a2044ba5866389067cfff529b064d1885ea36
> --- /dev/null
> +++ b/gcc/gimple-isel-match.pd
> @@ -0,0 +1,46 @@
> +/* Match-and-simplify patterns for GIMPLE folding during instruction selection.
> + This file is consumed by genmatch which produces gimple-isel-match.cc.
> +
> + Copyright (C) 2026 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/>. */
> +
> +
> +/* Generic tree predicates we inherit. */
> +(define_predicates
> + integer_onep integer_zerop integer_all_onesp integer_minus_onep
> + integer_each_onep integer_truep integer_nonzerop
> + real_zerop real_onep real_minus_onep
> + zerop
> + initializer_each_zero_or_onep
> + CONSTANT_CLASS_P
> + poly_int_tree_p
> + tree_expr_nonnegative_p
> + tree_expr_nonzero_p
> + integer_valued_real_p
> + integer_pow2p
> + uniform_integer_cst_p
> + HONOR_NANS
> + uniform_vector_p
> + expand_vec_cmp_expr_p
> + bitmask_inv_cst_vector_p)
> +
> +/* Operator lists. */
> +(define_operator_list tcc_comparison
> + lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt)
> +
> +#include "cfn-operators.pd"
We probably want to create a shared header we can include in both
match.pd and here to avoid maintaining this in two places?
> diff --git a/gcc/gimple-isel.cc b/gcc/gimple-isel.cc
> index b193e27b183e1a83d73369b629c81ea0d7db43cd..4348bd53103865c81a9e4c6f2ea434c7ef94f183 100644
> --- a/gcc/gimple-isel.cc
> +++ b/gcc/gimple-isel.cc
> @@ -40,6 +40,10 @@ along with GCC; see the file COPYING3. If not see
> #include "gimple-fold.h"
> #include "internal-fn.h"
> #include "fold-const.h"
> +#include "gimple-match.h"
> +
> +extern bool gimple_isel_simplify (gimple_match_op *, gimple_seq *,
> + tree (*) (tree));
>
> /* Expand all ARRAY_REF(VIEW_CONVERT_EXPR) gimple assignments into calls to
> internal function based on vector type of selected expansion.
> @@ -1360,6 +1364,15 @@ pass_gimple_isel::execute (struct function *fun)
> /* Give the target first try at replacing the instruction. */
> cfg_changed |= targetm.instruction_selection (fun, &gsi);
>
> + /* Apply gimple-isel-match.pd patterns. */
> + bool stmt_changed = fold_stmt (&gsi, gimple_isel_simplify);
But fold_stmt does a lot more than just apply *.pd patterns, why
not split out the relevant part,
gimple_seq seq = NULL;
gimple_match_op res_op;
if (gimple_simplify (stmt, &res_op, inplace ? NULL : &seq,
valueize, valueize)
&& replace_stmt_with_simplification (gsi, &res_op, &seq, inplace,
dce_worklist))
changed = true;
else
gimple_seq_discard (seq);
to a helper and use only that?
> + if (stmt_changed && !gsi_end_p (gsi))
I never seen gsi_end_p on a fold result. It's supposed to be
GIMPLE_NOP if "removed".
> + {
> + update_stmt (gsi_stmt (gsi));
> + if (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)
Do like forwprop:
if (gcond *cond = dyn_cast <gcond *> (stmt))
if (gimple_cond_true_p (cond)
|| gimple_cond_false_p (cond))
cfg_changed = true;
> + cfg_changed = true;
> + }
> +
> /* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
> calls mapping to supported optabs. */
> gimple *g = gimple_expand_vec_cond_expr (&gsi);
> @@ -1400,4 +1413,3 @@ make_pass_gimple_isel (gcc::context *ctxt)
> {
> return new pass_gimple_isel (ctxt);
> }
> -
>
>
>
@@ -228,6 +228,10 @@ 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))
+# The number of splits to be made for the gimple-isel-match.pd files.
+GIMPLE_ISEL_MATCH_PD_SEQ_SRC = $(patsubst %, gimple-isel-match-%.cc, $(MATCH_SPLITS_SEQ))
+GIMPLE_ISEL_MATCH_PD_SEQ_O = $(patsubst %, gimple-isel-match-%.o, $(MATCH_SPLITS_SEQ))
+
# The number of splits to be made for the insn-emit files.
NUM_INSNEMIT_SPLITS = @DEFAULT_INSNEMIT_PARTITIONS@
INSNEMIT_SPLITS_SEQ = $(wordlist 1,$(NUM_INSNEMIT_SPLITS),$(one_to_9999))
@@ -1401,6 +1405,7 @@ ANALYZER_OBJS = \
# the last objects to finish building.
OBJS = \
$(GIMPLE_MATCH_PD_SEQ_O) \
+ $(GIMPLE_ISEL_MATCH_PD_SEQ_O) \
gimple-match-exports.o \
$(GENERIC_MATCH_PD_SEQ_O) \
insn-attrtab.o \
@@ -1987,7 +1992,8 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
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_PD_SEQ_SRC) \
- $(GENERIC_MATCH_PD_SEQ_SRC) gimple-match-auto.h generic-match-auto.h \
+ $(GIMPLE_ISEL_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 \
@@ -2762,6 +2768,7 @@ $(common_out_object_file): $(common_out_file)
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_ISEL_MATCH_PD_SEQ_SRC) \
$(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \
gimple-match-auto.h generic-match-auto.h insn-target-def.h
@@ -3077,6 +3084,23 @@ s-generic-match: build/genmatch$(build_exeext) \
generic-match-auto.h
$(STAMP) s-generic-match
+# Add gimple-isel-match.pd
+$(GIMPLE_ISEL_MATCH_PD_SEQ_SRC): s-gimple-isel-match gimple-match-head.cc; @true
+gimple-isel-match-auto.h: s-gimple-isel-match; @true
+
+s-gimple-isel-match: build/genmatch$(build_exeext) \
+ $(srcdir)/gimple-isel-match.pd cfn-operators.pd
+ $(RUN_GEN) build/genmatch$(build_exeext) --gimple \
+ --header=tmp-gimple-isel-match-auto.h \
+ --include=gimple-isel-match-auto.h --namespace=isel \
+ $(srcdir)/gimple-isel-match.pd $(patsubst %, tmp-%, $(GIMPLE_ISEL_MATCH_PD_SEQ_SRC))
+ $(foreach id, $(MATCH_SPLITS_SEQ), \
+ $(SHELL) $(srcdir)/../move-if-change tmp-gimple-isel-match-$(id).cc \
+ gimple-isel-match-$(id).cc;)
+ $(SHELL) $(srcdir)/../move-if-change tmp-gimple-isel-match-auto.h \
+ gimple-isel-match-auto.h
+ $(STAMP) s-gimple-isel-match
+
GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(host_xm_file_list) \
$(OPTIONS_H_EXTRA) \
@@ -3216,6 +3240,7 @@ generated_files = config.h tm.h $(TM_P_H) $(TM_D_H) $(TM_JIT_H) $(TM_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_ISEL_MATCH_PD_SEQ_SRC) \
$(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 \
new file mode 100644
@@ -0,0 +1,46 @@
+/* Match-and-simplify patterns for GIMPLE folding during instruction selection.
+ This file is consumed by genmatch which produces gimple-isel-match.cc.
+
+ Copyright (C) 2026 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/>. */
+
+
+/* Generic tree predicates we inherit. */
+(define_predicates
+ integer_onep integer_zerop integer_all_onesp integer_minus_onep
+ integer_each_onep integer_truep integer_nonzerop
+ real_zerop real_onep real_minus_onep
+ zerop
+ initializer_each_zero_or_onep
+ CONSTANT_CLASS_P
+ poly_int_tree_p
+ tree_expr_nonnegative_p
+ tree_expr_nonzero_p
+ integer_valued_real_p
+ integer_pow2p
+ uniform_integer_cst_p
+ HONOR_NANS
+ uniform_vector_p
+ expand_vec_cmp_expr_p
+ bitmask_inv_cst_vector_p)
+
+/* Operator lists. */
+(define_operator_list tcc_comparison
+ lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt)
+
+#include "cfn-operators.pd"
@@ -40,6 +40,10 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-fold.h"
#include "internal-fn.h"
#include "fold-const.h"
+#include "gimple-match.h"
+
+extern bool gimple_isel_simplify (gimple_match_op *, gimple_seq *,
+ tree (*) (tree));
/* Expand all ARRAY_REF(VIEW_CONVERT_EXPR) gimple assignments into calls to
internal function based on vector type of selected expansion.
@@ -1360,6 +1364,15 @@ pass_gimple_isel::execute (struct function *fun)
/* Give the target first try at replacing the instruction. */
cfg_changed |= targetm.instruction_selection (fun, &gsi);
+ /* Apply gimple-isel-match.pd patterns. */
+ bool stmt_changed = fold_stmt (&gsi, gimple_isel_simplify);
+ if (stmt_changed && !gsi_end_p (gsi))
+ {
+ update_stmt (gsi_stmt (gsi));
+ if (gimple_code (gsi_stmt (gsi)) == GIMPLE_COND)
+ cfg_changed = true;
+ }
+
/* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
calls mapping to supported optabs. */
gimple *g = gimple_expand_vec_cond_expr (&gsi);
@@ -1400,4 +1413,3 @@ make_pass_gimple_isel (gcc::context *ctxt)
{
return new pass_gimple_isel (ctxt);
}
-