11debfc3dSmrg /* Generate code from machine description to perform peephole optimizations.
2*8feb0f0bSmrg Copyright (C) 1987-2020 Free Software Foundation, Inc.
31debfc3dSmrg
41debfc3dSmrg This file is part of GCC.
51debfc3dSmrg
61debfc3dSmrg GCC is free software; you can redistribute it and/or modify it under
71debfc3dSmrg the terms of the GNU General Public License as published by the Free
81debfc3dSmrg Software Foundation; either version 3, or (at your option) any later
91debfc3dSmrg version.
101debfc3dSmrg
111debfc3dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
121debfc3dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
131debfc3dSmrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141debfc3dSmrg for more details.
151debfc3dSmrg
161debfc3dSmrg You should have received a copy of the GNU General Public License
171debfc3dSmrg along with GCC; see the file COPYING3. If not see
181debfc3dSmrg <http://www.gnu.org/licenses/>. */
191debfc3dSmrg
201debfc3dSmrg
211debfc3dSmrg #include "bconfig.h"
221debfc3dSmrg #include "system.h"
231debfc3dSmrg #include "coretypes.h"
241debfc3dSmrg #include "tm.h"
251debfc3dSmrg #include "rtl.h"
261debfc3dSmrg #include "errors.h"
271debfc3dSmrg #include "gensupport.h"
281debfc3dSmrg
291debfc3dSmrg
301debfc3dSmrg /* While tree-walking an instruction pattern, we keep a chain
311debfc3dSmrg of these `struct link's to record how to get down to the
321debfc3dSmrg current position. In each one, POS is the operand number,
331debfc3dSmrg and if the operand is a vector VEC is the element number.
341debfc3dSmrg VEC is -1 if the operand is not a vector. */
351debfc3dSmrg
361debfc3dSmrg struct link
371debfc3dSmrg {
381debfc3dSmrg struct link *next;
391debfc3dSmrg int pos;
401debfc3dSmrg int vecelt;
411debfc3dSmrg };
421debfc3dSmrg
431debfc3dSmrg static int max_opno;
441debfc3dSmrg
451debfc3dSmrg /* Number of operands used in current peephole definition. */
461debfc3dSmrg
471debfc3dSmrg static int n_operands;
481debfc3dSmrg
491debfc3dSmrg static void match_rtx (rtx, struct link *, int);
501debfc3dSmrg static void print_path (struct link *);
511debfc3dSmrg static void print_code (RTX_CODE);
521debfc3dSmrg
531debfc3dSmrg static void
gen_peephole(md_rtx_info * info)541debfc3dSmrg gen_peephole (md_rtx_info *info)
551debfc3dSmrg {
561debfc3dSmrg rtx peep = info->def;
571debfc3dSmrg int ninsns = XVECLEN (peep, 0);
581debfc3dSmrg int i;
591debfc3dSmrg
601debfc3dSmrg n_operands = 0;
611debfc3dSmrg
621debfc3dSmrg printf (" insn = ins1;\n");
631debfc3dSmrg
641debfc3dSmrg for (i = 0; i < ninsns; i++)
651debfc3dSmrg {
661debfc3dSmrg if (i > 0)
671debfc3dSmrg {
681debfc3dSmrg printf (" do { insn = NEXT_INSN (insn);\n");
691debfc3dSmrg printf (" if (insn == 0) goto L%d; }\n", info->index);
701debfc3dSmrg printf (" while (NOTE_P (insn)\n");
711debfc3dSmrg printf ("\t || (NONJUMP_INSN_P (insn)\n");
721debfc3dSmrg printf ("\t && (GET_CODE (PATTERN (insn)) == USE\n");
731debfc3dSmrg printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n");
741debfc3dSmrg
751debfc3dSmrg printf (" if (LABEL_P (insn)\n\
761debfc3dSmrg || BARRIER_P (insn))\n goto L%d;\n", info->index);
771debfc3dSmrg }
781debfc3dSmrg
791debfc3dSmrg printf (" pat = PATTERN (insn);\n");
801debfc3dSmrg
811debfc3dSmrg /* Walk the insn's pattern, remembering at all times the path
821debfc3dSmrg down to the walking point. */
831debfc3dSmrg
841debfc3dSmrg match_rtx (XVECEXP (peep, 0, i), NULL, info->index);
851debfc3dSmrg }
861debfc3dSmrg
871debfc3dSmrg /* We get this far if the pattern matches.
881debfc3dSmrg Now test the extra condition. */
891debfc3dSmrg
901debfc3dSmrg if (XSTR (peep, 1) && XSTR (peep, 1)[0])
911debfc3dSmrg printf (" if (! (%s)) goto L%d;\n",
921debfc3dSmrg XSTR (peep, 1), info->index);
931debfc3dSmrg
941debfc3dSmrg /* If that matches, construct new pattern and put it in the first insn.
951debfc3dSmrg This new pattern will never be matched.
961debfc3dSmrg It exists only so that insn-extract can get the operands back.
971debfc3dSmrg So use a simple regular form: a PARALLEL containing a vector
981debfc3dSmrg of all the operands. */
991debfc3dSmrg
1001debfc3dSmrg printf (" PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
1011debfc3dSmrg
1021debfc3dSmrg /* Record this define_peephole's insn code in the insn,
1031debfc3dSmrg as if it had been recognized to match this. */
1041debfc3dSmrg printf (" INSN_CODE (ins1) = %d;\n", info->index);
1051debfc3dSmrg
1061debfc3dSmrg /* Delete the remaining insns. */
1071debfc3dSmrg if (ninsns > 1)
1081debfc3dSmrg printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n");
1091debfc3dSmrg
1101debfc3dSmrg /* See reload1.c for insertion of NOTE which guarantees that this
1111debfc3dSmrg cannot be zero. */
1121debfc3dSmrg printf (" return NEXT_INSN (insn);\n");
1131debfc3dSmrg
1141debfc3dSmrg printf (" L%d:\n\n", info->index);
1151debfc3dSmrg }
1161debfc3dSmrg
1171debfc3dSmrg static void
match_rtx(rtx x,struct link * path,int fail_label)1181debfc3dSmrg match_rtx (rtx x, struct link *path, int fail_label)
1191debfc3dSmrg {
1201debfc3dSmrg RTX_CODE code;
1211debfc3dSmrg int i;
1221debfc3dSmrg int len;
1231debfc3dSmrg const char *fmt;
1241debfc3dSmrg struct link link;
1251debfc3dSmrg
1261debfc3dSmrg if (x == 0)
1271debfc3dSmrg return;
1281debfc3dSmrg
1291debfc3dSmrg
1301debfc3dSmrg code = GET_CODE (x);
1311debfc3dSmrg
1321debfc3dSmrg switch (code)
1331debfc3dSmrg {
1341debfc3dSmrg case MATCH_OPERAND:
1351debfc3dSmrg if (XINT (x, 0) > max_opno)
1361debfc3dSmrg max_opno = XINT (x, 0);
1371debfc3dSmrg if (XINT (x, 0) >= n_operands)
1381debfc3dSmrg n_operands = 1 + XINT (x, 0);
1391debfc3dSmrg
1401debfc3dSmrg printf (" x = ");
1411debfc3dSmrg print_path (path);
1421debfc3dSmrg printf (";\n");
1431debfc3dSmrg
1441debfc3dSmrg printf (" operands[%d] = x;\n", XINT (x, 0));
1451debfc3dSmrg if (XSTR (x, 1) && XSTR (x, 1)[0])
1461debfc3dSmrg printf (" if (! %s (x, %smode)) goto L%d;\n",
1471debfc3dSmrg XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
1481debfc3dSmrg return;
1491debfc3dSmrg
1501debfc3dSmrg case MATCH_DUP:
1511debfc3dSmrg case MATCH_PAR_DUP:
1521debfc3dSmrg printf (" x = ");
1531debfc3dSmrg print_path (path);
1541debfc3dSmrg printf (";\n");
1551debfc3dSmrg
1561debfc3dSmrg printf (" if (!rtx_equal_p (operands[%d], x)) goto L%d;\n",
1571debfc3dSmrg XINT (x, 0), fail_label);
1581debfc3dSmrg return;
1591debfc3dSmrg
1601debfc3dSmrg case MATCH_OP_DUP:
1611debfc3dSmrg printf (" x = ");
1621debfc3dSmrg print_path (path);
1631debfc3dSmrg printf (";\n");
1641debfc3dSmrg
1651debfc3dSmrg printf (" if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0));
1661debfc3dSmrg printf (" || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n",
1671debfc3dSmrg XINT (x, 0), fail_label);
1681debfc3dSmrg printf (" operands[%d] = x;\n", XINT (x, 0));
1691debfc3dSmrg link.next = path;
1701debfc3dSmrg link.vecelt = -1;
1711debfc3dSmrg for (i = 0; i < XVECLEN (x, 1); i++)
1721debfc3dSmrg {
1731debfc3dSmrg link.pos = i;
1741debfc3dSmrg match_rtx (XVECEXP (x, 1, i), &link, fail_label);
1751debfc3dSmrg }
1761debfc3dSmrg return;
1771debfc3dSmrg
1781debfc3dSmrg case MATCH_OPERATOR:
1791debfc3dSmrg if (XINT (x, 0) > max_opno)
1801debfc3dSmrg max_opno = XINT (x, 0);
1811debfc3dSmrg if (XINT (x, 0) >= n_operands)
1821debfc3dSmrg n_operands = 1 + XINT (x, 0);
1831debfc3dSmrg
1841debfc3dSmrg printf (" x = ");
1851debfc3dSmrg print_path (path);
1861debfc3dSmrg printf (";\n");
1871debfc3dSmrg
1881debfc3dSmrg printf (" operands[%d] = x;\n", XINT (x, 0));
1891debfc3dSmrg if (XSTR (x, 1) && XSTR (x, 1)[0])
1901debfc3dSmrg printf (" if (! %s (x, %smode)) goto L%d;\n",
1911debfc3dSmrg XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
1921debfc3dSmrg link.next = path;
1931debfc3dSmrg link.vecelt = -1;
1941debfc3dSmrg for (i = 0; i < XVECLEN (x, 2); i++)
1951debfc3dSmrg {
1961debfc3dSmrg link.pos = i;
1971debfc3dSmrg match_rtx (XVECEXP (x, 2, i), &link, fail_label);
1981debfc3dSmrg }
1991debfc3dSmrg return;
2001debfc3dSmrg
2011debfc3dSmrg case MATCH_PARALLEL:
2021debfc3dSmrg if (XINT (x, 0) > max_opno)
2031debfc3dSmrg max_opno = XINT (x, 0);
2041debfc3dSmrg if (XINT (x, 0) >= n_operands)
2051debfc3dSmrg n_operands = 1 + XINT (x, 0);
2061debfc3dSmrg
2071debfc3dSmrg printf (" x = ");
2081debfc3dSmrg print_path (path);
2091debfc3dSmrg printf (";\n");
2101debfc3dSmrg
2111debfc3dSmrg printf (" if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label);
2121debfc3dSmrg printf (" operands[%d] = x;\n", XINT (x, 0));
2131debfc3dSmrg if (XSTR (x, 1) && XSTR (x, 1)[0])
2141debfc3dSmrg printf (" if (! %s (x, %smode)) goto L%d;\n",
2151debfc3dSmrg XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
2161debfc3dSmrg link.next = path;
2171debfc3dSmrg link.pos = 0;
2181debfc3dSmrg for (i = 0; i < XVECLEN (x, 2); i++)
2191debfc3dSmrg {
2201debfc3dSmrg link.vecelt = i;
2211debfc3dSmrg match_rtx (XVECEXP (x, 2, i), &link, fail_label);
2221debfc3dSmrg }
2231debfc3dSmrg return;
2241debfc3dSmrg
2251debfc3dSmrg default:
2261debfc3dSmrg break;
2271debfc3dSmrg }
2281debfc3dSmrg
2291debfc3dSmrg printf (" x = ");
2301debfc3dSmrg print_path (path);
2311debfc3dSmrg printf (";\n");
2321debfc3dSmrg
2331debfc3dSmrg printf (" if (GET_CODE (x) != ");
2341debfc3dSmrg print_code (code);
2351debfc3dSmrg printf (") goto L%d;\n", fail_label);
2361debfc3dSmrg
2371debfc3dSmrg if (GET_MODE (x) != VOIDmode)
2381debfc3dSmrg {
2391debfc3dSmrg printf (" if (GET_MODE (x) != %smode) goto L%d;\n",
2401debfc3dSmrg GET_MODE_NAME (GET_MODE (x)), fail_label);
2411debfc3dSmrg }
2421debfc3dSmrg
2431debfc3dSmrg link.next = path;
2441debfc3dSmrg link.vecelt = -1;
2451debfc3dSmrg fmt = GET_RTX_FORMAT (code);
2461debfc3dSmrg len = GET_RTX_LENGTH (code);
2471debfc3dSmrg for (i = 0; i < len; i++)
2481debfc3dSmrg {
2491debfc3dSmrg link.pos = i;
2501debfc3dSmrg if (fmt[i] == 'e' || fmt[i] == 'u')
2511debfc3dSmrg match_rtx (XEXP (x, i), &link, fail_label);
2521debfc3dSmrg else if (fmt[i] == 'E')
2531debfc3dSmrg {
2541debfc3dSmrg int j;
2551debfc3dSmrg printf (" if (XVECLEN (x, %d) != %d) goto L%d;\n",
2561debfc3dSmrg i, XVECLEN (x, i), fail_label);
2571debfc3dSmrg for (j = 0; j < XVECLEN (x, i); j++)
2581debfc3dSmrg {
2591debfc3dSmrg link.vecelt = j;
2601debfc3dSmrg match_rtx (XVECEXP (x, i, j), &link, fail_label);
2611debfc3dSmrg }
2621debfc3dSmrg }
2631debfc3dSmrg else if (fmt[i] == 'i')
2641debfc3dSmrg {
2651debfc3dSmrg /* Make sure that at run time `x' is the RTX we want to test. */
2661debfc3dSmrg if (i != 0)
2671debfc3dSmrg {
2681debfc3dSmrg printf (" x = ");
2691debfc3dSmrg print_path (path);
2701debfc3dSmrg printf (";\n");
2711debfc3dSmrg }
2721debfc3dSmrg
2731debfc3dSmrg printf (" if (XINT (x, %d) != %d) goto L%d;\n",
2741debfc3dSmrg i, XINT (x, i), fail_label);
2751debfc3dSmrg }
2761debfc3dSmrg else if (fmt[i] == 'r')
2771debfc3dSmrg {
2781debfc3dSmrg gcc_assert (i == 0);
2791debfc3dSmrg printf (" if (REGNO (x) != %d) goto L%d;\n",
2801debfc3dSmrg REGNO (x), fail_label);
2811debfc3dSmrg }
2821debfc3dSmrg else if (fmt[i] == 'w')
2831debfc3dSmrg {
2841debfc3dSmrg /* Make sure that at run time `x' is the RTX we want to test. */
2851debfc3dSmrg if (i != 0)
2861debfc3dSmrg {
2871debfc3dSmrg printf (" x = ");
2881debfc3dSmrg print_path (path);
2891debfc3dSmrg printf (";\n");
2901debfc3dSmrg }
2911debfc3dSmrg
2921debfc3dSmrg printf (" if (XWINT (x, %d) != ", i);
2931debfc3dSmrg printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i));
2941debfc3dSmrg printf (") goto L%d;\n", fail_label);
2951debfc3dSmrg }
2961debfc3dSmrg else if (fmt[i] == 's')
2971debfc3dSmrg {
2981debfc3dSmrg /* Make sure that at run time `x' is the RTX we want to test. */
2991debfc3dSmrg if (i != 0)
3001debfc3dSmrg {
3011debfc3dSmrg printf (" x = ");
3021debfc3dSmrg print_path (path);
3031debfc3dSmrg printf (";\n");
3041debfc3dSmrg }
3051debfc3dSmrg
3061debfc3dSmrg printf (" if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n",
3071debfc3dSmrg i, XSTR (x, i), fail_label);
3081debfc3dSmrg }
309a2dc1f3fSmrg else if (fmt[i] == 'p')
310a2dc1f3fSmrg /* Not going to support subregs for legacy define_peeholes. */
311a2dc1f3fSmrg gcc_unreachable ();
3121debfc3dSmrg }
3131debfc3dSmrg }
3141debfc3dSmrg
3151debfc3dSmrg /* Given a PATH, representing a path down the instruction's
3161debfc3dSmrg pattern from the root to a certain point, output code to
3171debfc3dSmrg evaluate to the rtx at that point. */
3181debfc3dSmrg
3191debfc3dSmrg static void
print_path(struct link * path)3201debfc3dSmrg print_path (struct link *path)
3211debfc3dSmrg {
3221debfc3dSmrg if (path == 0)
3231debfc3dSmrg printf ("pat");
3241debfc3dSmrg else if (path->vecelt >= 0)
3251debfc3dSmrg {
3261debfc3dSmrg printf ("XVECEXP (");
3271debfc3dSmrg print_path (path->next);
3281debfc3dSmrg printf (", %d, %d)", path->pos, path->vecelt);
3291debfc3dSmrg }
3301debfc3dSmrg else
3311debfc3dSmrg {
3321debfc3dSmrg printf ("XEXP (");
3331debfc3dSmrg print_path (path->next);
3341debfc3dSmrg printf (", %d)", path->pos);
3351debfc3dSmrg }
3361debfc3dSmrg }
3371debfc3dSmrg
3381debfc3dSmrg static void
print_code(RTX_CODE code)3391debfc3dSmrg print_code (RTX_CODE code)
3401debfc3dSmrg {
3411debfc3dSmrg const char *p1;
3421debfc3dSmrg for (p1 = GET_RTX_NAME (code); *p1; p1++)
3431debfc3dSmrg putchar (TOUPPER (*p1));
3441debfc3dSmrg }
3451debfc3dSmrg
3461debfc3dSmrg extern int main (int, const char **);
3471debfc3dSmrg
3481debfc3dSmrg int
main(int argc,const char ** argv)3491debfc3dSmrg main (int argc, const char **argv)
3501debfc3dSmrg {
3511debfc3dSmrg max_opno = -1;
3521debfc3dSmrg
3531debfc3dSmrg progname = "genpeep";
3541debfc3dSmrg
3551debfc3dSmrg if (!init_rtx_reader_args (argc, argv))
3561debfc3dSmrg return (FATAL_EXIT_CODE);
3571debfc3dSmrg
3581debfc3dSmrg printf ("/* Generated automatically by the program `genpeep'\n\
3591debfc3dSmrg from the machine description file `md'. */\n\n");
3601debfc3dSmrg
361a2dc1f3fSmrg printf ("#define IN_TARGET_CODE 1\n");
3621debfc3dSmrg printf ("#include \"config.h\"\n");
3631debfc3dSmrg printf ("#include \"system.h\"\n");
3641debfc3dSmrg printf ("#include \"coretypes.h\"\n");
3651debfc3dSmrg printf ("#include \"backend.h\"\n");
3661debfc3dSmrg printf ("#include \"tree.h\"\n");
3671debfc3dSmrg printf ("#include \"rtl.h\"\n");
3681debfc3dSmrg printf ("#include \"insn-config.h\"\n");
3691debfc3dSmrg printf ("#include \"alias.h\"\n");
3701debfc3dSmrg printf ("#include \"varasm.h\"\n");
3711debfc3dSmrg printf ("#include \"stor-layout.h\"\n");
3721debfc3dSmrg printf ("#include \"calls.h\"\n");
3731debfc3dSmrg printf ("#include \"memmodel.h\"\n");
3741debfc3dSmrg printf ("#include \"tm_p.h\"\n");
3751debfc3dSmrg printf ("#include \"regs.h\"\n");
3761debfc3dSmrg printf ("#include \"output.h\"\n");
3771debfc3dSmrg printf ("#include \"recog.h\"\n");
3781debfc3dSmrg printf ("#include \"except.h\"\n");
3791debfc3dSmrg printf ("#include \"diagnostic-core.h\"\n");
3801debfc3dSmrg printf ("#include \"flags.h\"\n");
3811debfc3dSmrg printf ("#include \"tm-constrs.h\"\n\n");
3821debfc3dSmrg
3831debfc3dSmrg printf ("extern rtx peep_operand[];\n\n");
3841debfc3dSmrg printf ("#define operands peep_operand\n\n");
3851debfc3dSmrg
3861debfc3dSmrg printf ("rtx_insn *\npeephole (rtx_insn *ins1)\n{\n");
3871debfc3dSmrg printf (" rtx_insn *insn ATTRIBUTE_UNUSED;\n");
3881debfc3dSmrg printf (" rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n");
3891debfc3dSmrg
3901debfc3dSmrg /* Early out: no peepholes for insns followed by barriers. */
3911debfc3dSmrg printf (" if (NEXT_INSN (ins1)\n");
3921debfc3dSmrg printf (" && BARRIER_P (NEXT_INSN (ins1)))\n");
3931debfc3dSmrg printf (" return 0;\n\n");
3941debfc3dSmrg
3951debfc3dSmrg /* Read the machine description. */
3961debfc3dSmrg
3971debfc3dSmrg md_rtx_info info;
3981debfc3dSmrg while (read_md_rtx (&info))
3991debfc3dSmrg switch (GET_CODE (info.def))
4001debfc3dSmrg {
4011debfc3dSmrg case DEFINE_PEEPHOLE:
4021debfc3dSmrg gen_peephole (&info);
4031debfc3dSmrg break;
4041debfc3dSmrg
4051debfc3dSmrg default:
4061debfc3dSmrg break;
4071debfc3dSmrg }
4081debfc3dSmrg
4091debfc3dSmrg printf (" return 0;\n}\n\n");
4101debfc3dSmrg
4111debfc3dSmrg if (max_opno == -1)
4121debfc3dSmrg max_opno = 1;
4131debfc3dSmrg
4141debfc3dSmrg printf ("rtx peep_operand[%d];\n", max_opno + 1);
4151debfc3dSmrg
4161debfc3dSmrg fflush (stdout);
4171debfc3dSmrg return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
4181debfc3dSmrg }
419