Home | History | Annotate | Line # | Download | only in gcc
      1 /* Generate code from machine description to perform peephole optimizations.
      2    Copyright (C) 1987-2022 Free Software Foundation, Inc.
      3 
      4 This file is part of GCC.
      5 
      6 GCC is free software; you can redistribute it and/or modify it under
      7 the terms of the GNU General Public License as published by the Free
      8 Software Foundation; either version 3, or (at your option) any later
      9 version.
     10 
     11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14 for more details.
     15 
     16 You should have received a copy of the GNU General Public License
     17 along with GCC; see the file COPYING3.  If not see
     18 <http://www.gnu.org/licenses/>.  */
     19 
     20 
     21 #include "bconfig.h"
     22 #include "system.h"
     23 #include "coretypes.h"
     24 #include "tm.h"
     25 #include "rtl.h"
     26 #include "errors.h"
     27 #include "gensupport.h"
     28 
     29 
     30 /* While tree-walking an instruction pattern, we keep a chain
     31    of these `struct link's to record how to get down to the
     32    current position.  In each one, POS is the operand number,
     33    and if the operand is a vector VEC is the element number.
     34    VEC is -1 if the operand is not a vector.  */
     35 
     36 struct link
     37 {
     38   struct link *next;
     39   int pos;
     40   int vecelt;
     41 };
     42 
     43 static int max_opno;
     44 
     45 /* Number of operands used in current peephole definition.  */
     46 
     47 static int n_operands;
     48 
     49 static void match_rtx (rtx, struct link *, int);
     50 static void print_path (struct link *);
     51 static void print_code (RTX_CODE);
     52 
     53 static void
     55 gen_peephole (md_rtx_info *info)
     56 {
     57   rtx peep = info->def;
     58   int ninsns = XVECLEN (peep, 0);
     59   int i;
     60 
     61   n_operands = 0;
     62 
     63   printf ("  insn = ins1;\n");
     64 
     65   for (i = 0; i < ninsns; i++)
     66     {
     67       if (i > 0)
     68 	{
     69 	  printf ("  do { insn = NEXT_INSN (insn);\n");
     70 	  printf ("       if (insn == 0) goto L%d; }\n", info->index);
     71 	  printf ("  while (NOTE_P (insn)\n");
     72 	  printf ("\t || (NONJUMP_INSN_P (insn)\n");
     73 	  printf ("\t     && (GET_CODE (PATTERN (insn)) == USE\n");
     74 	  printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n");
     75 
     76 	  printf ("  if (LABEL_P (insn)\n\
     77       || BARRIER_P (insn))\n    goto L%d;\n", info->index);
     78 	}
     79 
     80       printf ("  pat = PATTERN (insn);\n");
     81 
     82       /* Walk the insn's pattern, remembering at all times the path
     83 	 down to the walking point.  */
     84 
     85       match_rtx (XVECEXP (peep, 0, i), NULL, info->index);
     86     }
     87 
     88   /* We get this far if the pattern matches.
     89      Now test the extra condition.  */
     90 
     91   if (XSTR (peep, 1) && XSTR (peep, 1)[0])
     92     printf ("  if (! (%s)) goto L%d;\n",
     93 	    XSTR (peep, 1), info->index);
     94 
     95   /* If that matches, construct new pattern and put it in the first insn.
     96      This new pattern will never be matched.
     97      It exists only so that insn-extract can get the operands back.
     98      So use a simple regular form: a PARALLEL containing a vector
     99      of all the operands.  */
    100 
    101   printf ("  PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
    102 
    103   /* Record this define_peephole's insn code in the insn,
    104      as if it had been recognized to match this.  */
    105   printf ("  INSN_CODE (ins1) = %d;\n", info->index);
    106 
    107   /* Delete the remaining insns.  */
    108   if (ninsns > 1)
    109     printf ("  delete_for_peephole (NEXT_INSN (ins1), insn);\n");
    110 
    111   /* See reload1.cc for insertion of NOTE which guarantees that this
    112      cannot be zero.  */
    113   printf ("  return NEXT_INSN (insn);\n");
    114 
    115   printf (" L%d:\n\n", info->index);
    116 }
    117 
    118 static void
    120 match_rtx (rtx x, struct link *path, int fail_label)
    121 {
    122   RTX_CODE code;
    123   int i;
    124   int len;
    125   const char *fmt;
    126   struct link link;
    127 
    128   if (x == 0)
    129     return;
    130 
    131 
    132   code = GET_CODE (x);
    133 
    134   switch (code)
    135     {
    136     case MATCH_OPERAND:
    137       if (XINT (x, 0) > max_opno)
    138 	max_opno = XINT (x, 0);
    139       if (XINT (x, 0) >= n_operands)
    140 	n_operands = 1 + XINT (x, 0);
    141 
    142       printf ("  x = ");
    143       print_path (path);
    144       printf (";\n");
    145 
    146       printf ("  operands[%d] = x;\n", XINT (x, 0));
    147       if (XSTR (x, 1) && XSTR (x, 1)[0])
    148 	printf ("  if (! %s (x, %smode)) goto L%d;\n",
    149 		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
    150       return;
    151 
    152     case MATCH_DUP:
    153     case MATCH_PAR_DUP:
    154       printf ("  x = ");
    155       print_path (path);
    156       printf (";\n");
    157 
    158       printf ("  if (!rtx_equal_p (operands[%d], x)) goto L%d;\n",
    159 	      XINT (x, 0), fail_label);
    160       return;
    161 
    162     case MATCH_OP_DUP:
    163       printf ("  x = ");
    164       print_path (path);
    165       printf (";\n");
    166 
    167       printf ("  if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0));
    168       printf ("      || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n",
    169 	      XINT (x, 0), fail_label);
    170       printf ("  operands[%d] = x;\n", XINT (x, 0));
    171       link.next = path;
    172       link.vecelt = -1;
    173       for (i = 0; i < XVECLEN (x, 1); i++)
    174 	{
    175 	  link.pos = i;
    176 	  match_rtx (XVECEXP (x, 1, i), &link, fail_label);
    177 	}
    178       return;
    179 
    180     case MATCH_OPERATOR:
    181       if (XINT (x, 0) > max_opno)
    182 	max_opno = XINT (x, 0);
    183       if (XINT (x, 0) >= n_operands)
    184 	n_operands = 1 + XINT (x, 0);
    185 
    186       printf ("  x = ");
    187       print_path (path);
    188       printf (";\n");
    189 
    190       printf ("  operands[%d] = x;\n", XINT (x, 0));
    191       if (XSTR (x, 1) && XSTR (x, 1)[0])
    192 	printf ("  if (! %s (x, %smode)) goto L%d;\n",
    193 		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
    194       link.next = path;
    195       link.vecelt = -1;
    196       for (i = 0; i < XVECLEN (x, 2); i++)
    197 	{
    198 	  link.pos = i;
    199 	  match_rtx (XVECEXP (x, 2, i), &link, fail_label);
    200 	}
    201       return;
    202 
    203     case MATCH_PARALLEL:
    204       if (XINT (x, 0) > max_opno)
    205 	max_opno = XINT (x, 0);
    206       if (XINT (x, 0) >= n_operands)
    207 	n_operands = 1 + XINT (x, 0);
    208 
    209       printf ("  x = ");
    210       print_path (path);
    211       printf (";\n");
    212 
    213       printf ("  if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label);
    214       printf ("  operands[%d] = x;\n", XINT (x, 0));
    215       if (XSTR (x, 1) && XSTR (x, 1)[0])
    216 	printf ("  if (! %s (x, %smode)) goto L%d;\n",
    217 		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
    218       link.next = path;
    219       link.pos = 0;
    220       for (i = 0; i < XVECLEN (x, 2); i++)
    221 	{
    222 	  link.vecelt = i;
    223 	  match_rtx (XVECEXP (x, 2, i), &link, fail_label);
    224 	}
    225       return;
    226 
    227     default:
    228       break;
    229     }
    230 
    231   printf ("  x = ");
    232   print_path (path);
    233   printf (";\n");
    234 
    235   printf ("  if (GET_CODE (x) != ");
    236   print_code (code);
    237   printf (") goto L%d;\n", fail_label);
    238 
    239   if (GET_MODE (x) != VOIDmode)
    240     {
    241       printf ("  if (GET_MODE (x) != %smode) goto L%d;\n",
    242 	      GET_MODE_NAME (GET_MODE (x)), fail_label);
    243     }
    244 
    245   link.next = path;
    246   link.vecelt = -1;
    247   fmt = GET_RTX_FORMAT (code);
    248   len = GET_RTX_LENGTH (code);
    249   for (i = 0; i < len; i++)
    250     {
    251       link.pos = i;
    252       if (fmt[i] == 'e' || fmt[i] == 'u')
    253 	match_rtx (XEXP (x, i), &link, fail_label);
    254       else if (fmt[i] == 'E')
    255 	{
    256 	  int j;
    257 	  printf ("  if (XVECLEN (x, %d) != %d) goto L%d;\n",
    258 		  i, XVECLEN (x, i), fail_label);
    259 	  for (j = 0; j < XVECLEN (x, i); j++)
    260 	    {
    261 	      link.vecelt = j;
    262 	      match_rtx (XVECEXP (x, i, j), &link, fail_label);
    263 	    }
    264 	}
    265       else if (fmt[i] == 'i')
    266 	{
    267 	  /* Make sure that at run time `x' is the RTX we want to test.  */
    268 	  if (i != 0)
    269 	    {
    270 	      printf ("  x = ");
    271 	      print_path (path);
    272 	      printf (";\n");
    273 	    }
    274 
    275 	  printf ("  if (XINT (x, %d) != %d) goto L%d;\n",
    276 		  i, XINT (x, i), fail_label);
    277 	}
    278       else if (fmt[i] == 'r')
    279 	{
    280 	  gcc_assert (i == 0);
    281 	  printf ("  if (REGNO (x) != %d) goto L%d;\n",
    282 		  REGNO (x), fail_label);
    283 	}
    284       else if (fmt[i] == 'w')
    285 	{
    286 	  /* Make sure that at run time `x' is the RTX we want to test.  */
    287 	  if (i != 0)
    288 	    {
    289 	      printf ("  x = ");
    290 	      print_path (path);
    291 	      printf (";\n");
    292 	    }
    293 
    294 	  printf ("  if (XWINT (x, %d) != ", i);
    295 	  printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i));
    296 	  printf (") goto L%d;\n", fail_label);
    297 	}
    298       else if (fmt[i] == 's')
    299 	{
    300 	  /* Make sure that at run time `x' is the RTX we want to test.  */
    301 	  if (i != 0)
    302 	    {
    303 	      printf ("  x = ");
    304 	      print_path (path);
    305 	      printf (";\n");
    306 	    }
    307 
    308 	  printf ("  if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n",
    309 		  i, XSTR (x, i), fail_label);
    310 	}
    311       else if (fmt[i] == 'p')
    312 	/* Not going to support subregs for legacy define_peeholes.  */
    313 	gcc_unreachable ();
    314     }
    315 }
    316 
    317 /* Given a PATH, representing a path down the instruction's
    318    pattern from the root to a certain point, output code to
    319    evaluate to the rtx at that point.  */
    320 
    321 static void
    322 print_path (struct link *path)
    323 {
    324   if (path == 0)
    325     printf ("pat");
    326   else if (path->vecelt >= 0)
    327     {
    328       printf ("XVECEXP (");
    329       print_path (path->next);
    330       printf (", %d, %d)", path->pos, path->vecelt);
    331     }
    332   else
    333     {
    334       printf ("XEXP (");
    335       print_path (path->next);
    336       printf (", %d)", path->pos);
    337     }
    338 }
    339 
    340 static void
    342 print_code (RTX_CODE code)
    343 {
    344   const char *p1;
    345   for (p1 = GET_RTX_NAME (code); *p1; p1++)
    346     putchar (TOUPPER (*p1));
    347 }
    348 
    349 extern int main (int, const char **);
    350 
    351 int
    352 main (int argc, const char **argv)
    353 {
    354   max_opno = -1;
    355 
    356   progname = "genpeep";
    357 
    358   if (!init_rtx_reader_args (argc, argv))
    359     return (FATAL_EXIT_CODE);
    360 
    361   printf ("/* Generated automatically by the program `genpeep'\n\
    362 from the machine description file `md'.  */\n\n");
    363 
    364   printf ("#define IN_TARGET_CODE 1\n");
    365   printf ("#include \"config.h\"\n");
    366   printf ("#include \"system.h\"\n");
    367   printf ("#include \"coretypes.h\"\n");
    368   printf ("#include \"backend.h\"\n");
    369   printf ("#include \"tree.h\"\n");
    370   printf ("#include \"rtl.h\"\n");
    371   printf ("#include \"insn-config.h\"\n");
    372   printf ("#include \"alias.h\"\n");
    373   printf ("#include \"varasm.h\"\n");
    374   printf ("#include \"stor-layout.h\"\n");
    375   printf ("#include \"calls.h\"\n");
    376   printf ("#include \"memmodel.h\"\n");
    377   printf ("#include \"tm_p.h\"\n");
    378   printf ("#include \"regs.h\"\n");
    379   printf ("#include \"output.h\"\n");
    380   printf ("#include \"recog.h\"\n");
    381   printf ("#include \"except.h\"\n");
    382   printf ("#include \"diagnostic-core.h\"\n");
    383   printf ("#include \"flags.h\"\n");
    384   printf ("#include \"tm-constrs.h\"\n\n");
    385 
    386   printf ("extern rtx peep_operand[];\n\n");
    387   printf ("#define operands peep_operand\n\n");
    388 
    389   printf ("rtx_insn *\npeephole (rtx_insn *ins1)\n{\n");
    390   printf ("  rtx_insn *insn ATTRIBUTE_UNUSED;\n");
    391   printf ("  rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n");
    392 
    393   /* Early out: no peepholes for insns followed by barriers.  */
    394   printf ("  if (NEXT_INSN (ins1)\n");
    395   printf ("      && BARRIER_P (NEXT_INSN (ins1)))\n");
    396   printf ("    return 0;\n\n");
    397 
    398   /* Read the machine description.  */
    399 
    400   md_rtx_info info;
    401   while (read_md_rtx (&info))
    402     switch (GET_CODE (info.def))
    403       {
    404       case DEFINE_PEEPHOLE:
    405 	gen_peephole (&info);
    406 	break;
    407 
    408       default:
    409 	break;
    410       }
    411 
    412   printf ("  return 0;\n}\n\n");
    413 
    414   if (max_opno == -1)
    415     max_opno = 1;
    416 
    417   printf ("rtx peep_operand[%d];\n", max_opno + 1);
    418 
    419   fflush (stdout);
    420   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
    421 }
    422