118334Speter/* Generate code from machine description to perform peephole optimizations.
290075Sobrien   Copyright (C) 1987, 1989, 1992, 1997, 1998,
3169689Skan   1999, 2000, 2003, 2004 Free Software Foundation, Inc.
418334Speter
590075SobrienThis file is part of GCC.
618334Speter
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1118334Speter
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20169689Skan02110-1301, USA.  */
2118334Speter
2218334Speter
23132718Skan#include "bconfig.h"
2450397Sobrien#include "system.h"
25132718Skan#include "coretypes.h"
26132718Skan#include "tm.h"
2718334Speter#include "rtl.h"
2890075Sobrien#include "errors.h"
2990075Sobrien#include "gensupport.h"
3018334Speter
3118334Speter
3218334Speter/* While tree-walking an instruction pattern, we keep a chain
3318334Speter   of these `struct link's to record how to get down to the
3418334Speter   current position.  In each one, POS is the operand number,
3518334Speter   and if the operand is a vector VEC is the element number.
3618334Speter   VEC is -1 if the operand is not a vector.  */
3718334Speter
3818334Speterstruct link
3918334Speter{
4018334Speter  struct link *next;
4118334Speter  int pos;
4218334Speter  int vecelt;
4318334Speter};
4418334Speter
4518334Speterstatic int max_opno;
4618334Speter
4718334Speter/* Number of operands used in current peephole definition.  */
4818334Speter
4918334Speterstatic int n_operands;
5018334Speter
5118334Speter/* Peephole optimizations get insn codes just like insn patterns.
5218334Speter   Count them so we know the code of the define_peephole we are handling.  */
5318334Speter
5418334Speterstatic int insn_code_number = 0;
5518334Speter
56132718Skanstatic void gen_peephole (rtx);
57132718Skanstatic void match_rtx (rtx, struct link *, int);
58132718Skanstatic void print_path (struct link *);
59132718Skanstatic void print_code (RTX_CODE);
6018334Speter
6118334Speterstatic void
62132718Skangen_peephole (rtx peep)
6318334Speter{
6418334Speter  int ninsns = XVECLEN (peep, 0);
6518334Speter  int i;
6618334Speter
6718334Speter  n_operands = 0;
6818334Speter
6918334Speter  printf ("  insn = ins1;\n");
7018334Speter
7118334Speter  for (i = 0; i < ninsns; i++)
7218334Speter    {
7318334Speter      if (i > 0)
7418334Speter	{
7518334Speter	  printf ("  do { insn = NEXT_INSN (insn);\n");
7618334Speter	  printf ("       if (insn == 0) goto L%d; }\n",
7718334Speter		  insn_code_number);
78169689Skan	  printf ("  while (NOTE_P (insn)\n");
79169689Skan	  printf ("\t || (NONJUMP_INSN_P (insn)\n");
8018334Speter	  printf ("\t     && (GET_CODE (PATTERN (insn)) == USE\n");
8118334Speter	  printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n");
8218334Speter
83169689Skan	  printf ("  if (LABEL_P (insn)\n\
84169689Skan      || BARRIER_P (insn))\n    goto L%d;\n",
85132718Skan		  insn_code_number);
8618334Speter	}
8718334Speter
8818334Speter      printf ("  pat = PATTERN (insn);\n");
8918334Speter
9018334Speter      /* Walk the insn's pattern, remembering at all times the path
9118334Speter	 down to the walking point.  */
9218334Speter
9390075Sobrien      match_rtx (XVECEXP (peep, 0, i), NULL, insn_code_number);
9418334Speter    }
9518334Speter
9618334Speter  /* We get this far if the pattern matches.
9718334Speter     Now test the extra condition.  */
9818334Speter
9918334Speter  if (XSTR (peep, 1) && XSTR (peep, 1)[0])
10018334Speter    printf ("  if (! (%s)) goto L%d;\n",
10118334Speter	    XSTR (peep, 1), insn_code_number);
10218334Speter
10318334Speter  /* If that matches, construct new pattern and put it in the first insn.
10418334Speter     This new pattern will never be matched.
10518334Speter     It exists only so that insn-extract can get the operands back.
10618334Speter     So use a simple regular form: a PARALLEL containing a vector
10718334Speter     of all the operands.  */
10818334Speter
10950397Sobrien  printf ("  PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
11018334Speter
11118334Speter  /* Record this define_peephole's insn code in the insn,
11218334Speter     as if it had been recognized to match this.  */
11318334Speter  printf ("  INSN_CODE (ins1) = %d;\n",
11418334Speter	  insn_code_number);
11518334Speter
11618334Speter  /* Delete the remaining insns.  */
11718334Speter  if (ninsns > 1)
11818334Speter    printf ("  delete_for_peephole (NEXT_INSN (ins1), insn);\n");
11918334Speter
12018334Speter  /* See reload1.c for insertion of NOTE which guarantees that this
12118334Speter     cannot be zero.  */
12218334Speter  printf ("  return NEXT_INSN (insn);\n");
12318334Speter
12418334Speter  printf (" L%d:\n\n", insn_code_number);
12518334Speter}
12618334Speter
12718334Speterstatic void
128132718Skanmatch_rtx (rtx x, struct link *path, int fail_label)
12918334Speter{
13090075Sobrien  RTX_CODE code;
13190075Sobrien  int i;
13290075Sobrien  int len;
13390075Sobrien  const char *fmt;
13418334Speter  struct link link;
13518334Speter
13618334Speter  if (x == 0)
13718334Speter    return;
13818334Speter
13918334Speter
14018334Speter  code = GET_CODE (x);
14118334Speter
14218334Speter  switch (code)
14318334Speter    {
14418334Speter    case MATCH_OPERAND:
14518334Speter      if (XINT (x, 0) > max_opno)
14618334Speter	max_opno = XINT (x, 0);
14718334Speter      if (XINT (x, 0) >= n_operands)
14818334Speter	n_operands = 1 + XINT (x, 0);
14918334Speter
15018334Speter      printf ("  x = ");
15118334Speter      print_path (path);
15218334Speter      printf (";\n");
15318334Speter
15418334Speter      printf ("  operands[%d] = x;\n", XINT (x, 0));
15518334Speter      if (XSTR (x, 1) && XSTR (x, 1)[0])
15618334Speter	printf ("  if (! %s (x, %smode)) goto L%d;\n",
15718334Speter		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
15818334Speter      return;
15918334Speter
16018334Speter    case MATCH_DUP:
16118334Speter    case MATCH_PAR_DUP:
16218334Speter      printf ("  x = ");
16318334Speter      print_path (path);
16418334Speter      printf (";\n");
16518334Speter
16618334Speter      printf ("  if (!rtx_equal_p (operands[%d], x)) goto L%d;\n",
16718334Speter	      XINT (x, 0), fail_label);
16818334Speter      return;
16918334Speter
17018334Speter    case MATCH_OP_DUP:
17118334Speter      printf ("  x = ");
17218334Speter      print_path (path);
17318334Speter      printf (";\n");
17418334Speter
17518334Speter      printf ("  if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0));
17618334Speter      printf ("      || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n",
17718334Speter	      XINT (x, 0), fail_label);
17818334Speter      printf ("  operands[%d] = x;\n", XINT (x, 0));
17918334Speter      link.next = path;
18018334Speter      link.vecelt = -1;
18118334Speter      for (i = 0; i < XVECLEN (x, 1); i++)
18218334Speter	{
18318334Speter	  link.pos = i;
18418334Speter	  match_rtx (XVECEXP (x, 1, i), &link, fail_label);
18518334Speter	}
18618334Speter      return;
18718334Speter
18818334Speter    case MATCH_OPERATOR:
18918334Speter      if (XINT (x, 0) > max_opno)
19018334Speter	max_opno = XINT (x, 0);
19118334Speter      if (XINT (x, 0) >= n_operands)
19218334Speter	n_operands = 1 + XINT (x, 0);
19318334Speter
19418334Speter      printf ("  x = ");
19518334Speter      print_path (path);
19618334Speter      printf (";\n");
19718334Speter
19818334Speter      printf ("  operands[%d] = x;\n", XINT (x, 0));
19918334Speter      if (XSTR (x, 1) && XSTR (x, 1)[0])
20018334Speter	printf ("  if (! %s (x, %smode)) goto L%d;\n",
20118334Speter		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
20218334Speter      link.next = path;
20318334Speter      link.vecelt = -1;
20418334Speter      for (i = 0; i < XVECLEN (x, 2); i++)
20518334Speter	{
20618334Speter	  link.pos = i;
20718334Speter	  match_rtx (XVECEXP (x, 2, i), &link, fail_label);
20818334Speter	}
20918334Speter      return;
21018334Speter
21118334Speter    case MATCH_PARALLEL:
21218334Speter      if (XINT (x, 0) > max_opno)
21318334Speter	max_opno = XINT (x, 0);
21418334Speter      if (XINT (x, 0) >= n_operands)
21518334Speter	n_operands = 1 + XINT (x, 0);
21618334Speter
21718334Speter      printf ("  x = ");
21818334Speter      print_path (path);
21918334Speter      printf (";\n");
22018334Speter
22118334Speter      printf ("  if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label);
22218334Speter      printf ("  operands[%d] = x;\n", XINT (x, 0));
22318334Speter      if (XSTR (x, 1) && XSTR (x, 1)[0])
22418334Speter	printf ("  if (! %s (x, %smode)) goto L%d;\n",
22518334Speter		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
22618334Speter      link.next = path;
22718334Speter      link.pos = 0;
22818334Speter      for (i = 0; i < XVECLEN (x, 2); i++)
22918334Speter	{
23018334Speter	  link.vecelt = i;
23118334Speter	  match_rtx (XVECEXP (x, 2, i), &link, fail_label);
23218334Speter	}
23318334Speter      return;
23418334Speter
23518334Speter    case ADDRESS:
23618334Speter      match_rtx (XEXP (x, 0), path, fail_label);
23718334Speter      return;
238132718Skan
23950397Sobrien    default:
24050397Sobrien      break;
24118334Speter    }
24218334Speter
24318334Speter  printf ("  x = ");
24418334Speter  print_path (path);
24518334Speter  printf (";\n");
24618334Speter
24718334Speter  printf ("  if (GET_CODE (x) != ");
24818334Speter  print_code (code);
24918334Speter  printf (") goto L%d;\n", fail_label);
25018334Speter
25118334Speter  if (GET_MODE (x) != VOIDmode)
25218334Speter    {
25318334Speter      printf ("  if (GET_MODE (x) != %smode) goto L%d;\n",
25418334Speter	      GET_MODE_NAME (GET_MODE (x)), fail_label);
25518334Speter    }
25618334Speter
25718334Speter  link.next = path;
25818334Speter  link.vecelt = -1;
25918334Speter  fmt = GET_RTX_FORMAT (code);
26018334Speter  len = GET_RTX_LENGTH (code);
26118334Speter  for (i = 0; i < len; i++)
26218334Speter    {
26318334Speter      link.pos = i;
26418334Speter      if (fmt[i] == 'e' || fmt[i] == 'u')
26518334Speter	match_rtx (XEXP (x, i), &link, fail_label);
26618334Speter      else if (fmt[i] == 'E')
26718334Speter	{
26818334Speter	  int j;
26918334Speter	  printf ("  if (XVECLEN (x, %d) != %d) goto L%d;\n",
27018334Speter		  i, XVECLEN (x, i), fail_label);
27118334Speter	  for (j = 0; j < XVECLEN (x, i); j++)
27218334Speter	    {
27318334Speter	      link.vecelt = j;
27418334Speter	      match_rtx (XVECEXP (x, i, j), &link, fail_label);
27518334Speter	    }
27618334Speter	}
27718334Speter      else if (fmt[i] == 'i')
27818334Speter	{
27918334Speter	  /* Make sure that at run time `x' is the RTX we want to test.  */
28018334Speter	  if (i != 0)
28118334Speter	    {
28218334Speter	      printf ("  x = ");
28318334Speter	      print_path (path);
28418334Speter	      printf (";\n");
28518334Speter	    }
28618334Speter
28718334Speter	  printf ("  if (XINT (x, %d) != %d) goto L%d;\n",
28818334Speter		  i, XINT (x, i), fail_label);
28918334Speter	}
29018334Speter      else if (fmt[i] == 'w')
29118334Speter	{
29218334Speter	  /* Make sure that at run time `x' is the RTX we want to test.  */
29318334Speter	  if (i != 0)
29418334Speter	    {
29518334Speter	      printf ("  x = ");
29618334Speter	      print_path (path);
29718334Speter	      printf (";\n");
29818334Speter	    }
29918334Speter
30050397Sobrien	  printf ("  if (XWINT (x, %d) != ", i);
30150397Sobrien	  printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i));
30250397Sobrien	  printf (") goto L%d;\n", fail_label);
30318334Speter	}
30418334Speter      else if (fmt[i] == 's')
30518334Speter	{
30618334Speter	  /* Make sure that at run time `x' is the RTX we want to test.  */
30718334Speter	  if (i != 0)
30818334Speter	    {
30918334Speter	      printf ("  x = ");
31018334Speter	      print_path (path);
31118334Speter	      printf (";\n");
31218334Speter	    }
31318334Speter
31418334Speter	  printf ("  if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n",
31518334Speter		  i, XSTR (x, i), fail_label);
31618334Speter	}
31718334Speter    }
31818334Speter}
31918334Speter
32018334Speter/* Given a PATH, representing a path down the instruction's
32118334Speter   pattern from the root to a certain point, output code to
32218334Speter   evaluate to the rtx at that point.  */
32318334Speter
32418334Speterstatic void
325132718Skanprint_path (struct link *path)
32618334Speter{
32718334Speter  if (path == 0)
32818334Speter    printf ("pat");
32918334Speter  else if (path->vecelt >= 0)
33018334Speter    {
33118334Speter      printf ("XVECEXP (");
33218334Speter      print_path (path->next);
33318334Speter      printf (", %d, %d)", path->pos, path->vecelt);
33418334Speter    }
33518334Speter  else
33618334Speter    {
33718334Speter      printf ("XEXP (");
33818334Speter      print_path (path->next);
33918334Speter      printf (", %d)", path->pos);
34018334Speter    }
34118334Speter}
34218334Speter
34318334Speterstatic void
344132718Skanprint_code (RTX_CODE code)
34518334Speter{
34690075Sobrien  const char *p1;
34718334Speter  for (p1 = GET_RTX_NAME (code); *p1; p1++)
34890075Sobrien    putchar (TOUPPER(*p1));
34918334Speter}
35018334Speter
351132718Skanextern int main (int, char **);
35218334Speter
35318334Speterint
354132718Skanmain (int argc, char **argv)
35518334Speter{
35618334Speter  rtx desc;
35718334Speter
35818334Speter  max_opno = -1;
35918334Speter
36090075Sobrien  progname = "genpeep";
36118334Speter
36290075Sobrien  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
36390075Sobrien    return (FATAL_EXIT_CODE);
36418334Speter
36518334Speter  printf ("/* Generated automatically by the program `genpeep'\n\
36618334Speterfrom the machine description file `md'.  */\n\n");
36718334Speter
36818334Speter  printf ("#include \"config.h\"\n");
36950397Sobrien  printf ("#include \"system.h\"\n");
370132718Skan  printf ("#include \"coretypes.h\"\n");
371132718Skan  printf ("#include \"tm.h\"\n");
37252284Sobrien  printf ("#include \"insn-config.h\"\n");
37318334Speter  printf ("#include \"rtl.h\"\n");
37490075Sobrien  printf ("#include \"tm_p.h\"\n");
37518334Speter  printf ("#include \"regs.h\"\n");
37618334Speter  printf ("#include \"output.h\"\n");
37750397Sobrien  printf ("#include \"real.h\"\n");
37852284Sobrien  printf ("#include \"recog.h\"\n");
379169689Skan  printf ("#include \"except.h\"\n");
380169689Skan  printf ("#include \"function.h\"\n");
381169689Skan  printf ("#include \"toplev.h\"\n");
382169689Skan  printf ("#include \"flags.h\"\n");
383169689Skan  printf ("#include \"tm-constrs.h\"\n\n");
38418334Speter
38590075Sobrien  printf ("#ifdef HAVE_peephole\n");
38618334Speter  printf ("extern rtx peep_operand[];\n\n");
38718334Speter  printf ("#define operands peep_operand\n\n");
38818334Speter
389132718Skan  printf ("rtx\npeephole (rtx ins1)\n{\n");
39050397Sobrien  printf ("  rtx insn ATTRIBUTE_UNUSED, x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n");
39118334Speter
39218334Speter  /* Early out: no peepholes for insns followed by barriers.  */
39318334Speter  printf ("  if (NEXT_INSN (ins1)\n");
394169689Skan  printf ("      && BARRIER_P (NEXT_INSN (ins1)))\n");
39518334Speter  printf ("    return 0;\n\n");
39618334Speter
39718334Speter  /* Read the machine description.  */
39818334Speter
39918334Speter  while (1)
40018334Speter    {
40190075Sobrien      int line_no, rtx_number = 0;
40290075Sobrien
40390075Sobrien      desc = read_md_rtx (&line_no, &rtx_number);
40490075Sobrien      if (desc == NULL)
40518334Speter	break;
40618334Speter
40790075Sobrien       if (GET_CODE (desc) == DEFINE_PEEPHOLE)
40818334Speter	{
40918334Speter	  gen_peephole (desc);
41018334Speter	  insn_code_number++;
41118334Speter	}
41218334Speter      if (GET_CODE (desc) == DEFINE_INSN
41318334Speter	  || GET_CODE (desc) == DEFINE_EXPAND
41490075Sobrien	  || GET_CODE (desc) == DEFINE_SPLIT
41590075Sobrien	  || GET_CODE (desc) == DEFINE_PEEPHOLE2)
41618334Speter	{
41718334Speter	  insn_code_number++;
41818334Speter	}
41918334Speter    }
42018334Speter
42118334Speter  printf ("  return 0;\n}\n\n");
42218334Speter
42318334Speter  if (max_opno == -1)
42418334Speter    max_opno = 1;
42518334Speter
42618334Speter  printf ("rtx peep_operand[%d];\n", max_opno + 1);
42790075Sobrien  printf ("#endif\n");
42818334Speter
42918334Speter  fflush (stdout);
43090075Sobrien  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
43118334Speter}
432