118334Speter/* Generate code from machine description to emit insns as rtl.
2132718Skan   Copyright (C) 1987, 1988, 1991, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
3169689Skan   2003, 2004, 2005 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
3218334Speterstatic int max_opno;
3318334Speterstatic int max_dup_opno;
3490075Sobrienstatic int max_scratch_opno;
3518334Speterstatic int insn_code_number;
3618334Speterstatic int insn_index_number;
3718334Speter
3818334Speter/* Data structure for recording the patterns of insns that have CLOBBERs.
39132718Skan   We use this to output a function that adds these CLOBBERs to a
4018334Speter   previously-allocated PARALLEL expression.  */
4118334Speter
4218334Speterstruct clobber_pat
4318334Speter{
4418334Speter  struct clobber_ent *insns;
4518334Speter  rtx pattern;
4618334Speter  int first_clobber;
4718334Speter  struct clobber_pat *next;
4890075Sobrien  int has_hard_reg;
4918334Speter} *clobber_list;
5018334Speter
5118334Speter/* Records one insn that uses the clobber list.  */
5218334Speter
5318334Speterstruct clobber_ent
5418334Speter{
5518334Speter  int code_number;		/* Counts only insns.  */
5618334Speter  struct clobber_ent *next;
5718334Speter};
5818334Speter
59132718Skanstatic void max_operand_1		(rtx);
60132718Skanstatic int max_operand_vec		(rtx, int);
61132718Skanstatic void print_code			(RTX_CODE);
62132718Skanstatic void gen_exp			(rtx, enum rtx_code, char *);
63132718Skanstatic void gen_insn			(rtx, int);
64132718Skanstatic void gen_expand			(rtx);
65132718Skanstatic void gen_split			(rtx);
66132718Skanstatic void output_add_clobbers		(void);
67132718Skanstatic void output_added_clobbers_hard_reg_p (void);
68132718Skanstatic void gen_rtx_scratch		(rtx, enum rtx_code);
69132718Skanstatic void output_peephole2_scratches	(rtx);
7050397Sobrien
7150397Sobrien
7218334Speterstatic void
73132718Skanmax_operand_1 (rtx x)
7418334Speter{
7590075Sobrien  RTX_CODE code;
7690075Sobrien  int i;
7790075Sobrien  int len;
7890075Sobrien  const char *fmt;
7918334Speter
8018334Speter  if (x == 0)
8118334Speter    return;
8218334Speter
8318334Speter  code = GET_CODE (x);
8418334Speter
8518334Speter  if (code == MATCH_OPERAND || code == MATCH_OPERATOR
8618334Speter      || code == MATCH_PARALLEL)
8718334Speter    max_opno = MAX (max_opno, XINT (x, 0));
8818334Speter  if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)
8918334Speter    max_dup_opno = MAX (max_dup_opno, XINT (x, 0));
9090075Sobrien  if (code == MATCH_SCRATCH)
9190075Sobrien    max_scratch_opno = MAX (max_scratch_opno, XINT (x, 0));
9218334Speter
9318334Speter  fmt = GET_RTX_FORMAT (code);
9418334Speter  len = GET_RTX_LENGTH (code);
9518334Speter  for (i = 0; i < len; i++)
9618334Speter    {
9718334Speter      if (fmt[i] == 'e' || fmt[i] == 'u')
9818334Speter	max_operand_1 (XEXP (x, i));
9918334Speter      else if (fmt[i] == 'E')
10018334Speter	{
10118334Speter	  int j;
10218334Speter	  for (j = 0; j < XVECLEN (x, i); j++)
10318334Speter	    max_operand_1 (XVECEXP (x, i, j));
10418334Speter	}
10518334Speter    }
10618334Speter}
10718334Speter
10818334Speterstatic int
109132718Skanmax_operand_vec (rtx insn, int arg)
11018334Speter{
11190075Sobrien  int len = XVECLEN (insn, arg);
11290075Sobrien  int i;
11318334Speter
11418334Speter  max_opno = -1;
11518334Speter  max_dup_opno = -1;
11690075Sobrien  max_scratch_opno = -1;
11718334Speter
11818334Speter  for (i = 0; i < len; i++)
11918334Speter    max_operand_1 (XVECEXP (insn, arg, i));
12018334Speter
12118334Speter  return max_opno + 1;
12218334Speter}
12318334Speter
12418334Speterstatic void
125132718Skanprint_code (RTX_CODE code)
12618334Speter{
12790075Sobrien  const char *p1;
12818334Speter  for (p1 = GET_RTX_NAME (code); *p1; p1++)
12990075Sobrien    putchar (TOUPPER(*p1));
13090075Sobrien}
13190075Sobrien
13290075Sobrienstatic void
133132718Skangen_rtx_scratch (rtx x, enum rtx_code subroutine_type)
13490075Sobrien{
13590075Sobrien  if (subroutine_type == DEFINE_PEEPHOLE2)
13618334Speter    {
13790075Sobrien      printf ("operand%d", XINT (x, 0));
13818334Speter    }
13990075Sobrien  else
14090075Sobrien    {
14190075Sobrien      printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
14290075Sobrien    }
14318334Speter}
14418334Speter
14518334Speter/* Print a C expression to construct an RTX just like X,
14618334Speter   substituting any operand references appearing within.  */
14718334Speter
14818334Speterstatic void
149132718Skangen_exp (rtx x, enum rtx_code subroutine_type, char *used)
15018334Speter{
15190075Sobrien  RTX_CODE code;
15290075Sobrien  int i;
15390075Sobrien  int len;
15490075Sobrien  const char *fmt;
15518334Speter
15618334Speter  if (x == 0)
15718334Speter    {
15818334Speter      printf ("NULL_RTX");
15918334Speter      return;
16018334Speter    }
16118334Speter
16218334Speter  code = GET_CODE (x);
16318334Speter
16418334Speter  switch (code)
16518334Speter    {
16618334Speter    case MATCH_OPERAND:
16718334Speter    case MATCH_DUP:
16896263Sobrien      if (used)
16996263Sobrien	{
17096263Sobrien	  if (used[XINT (x, 0)])
17196263Sobrien	    {
17296263Sobrien	      printf ("copy_rtx (operand%d)", XINT (x, 0));
17396263Sobrien	      return;
17496263Sobrien	    }
17596263Sobrien	  used[XINT (x, 0)] = 1;
17696263Sobrien	}
17718334Speter      printf ("operand%d", XINT (x, 0));
17818334Speter      return;
17918334Speter
18018334Speter    case MATCH_OP_DUP:
181169689Skan      printf ("gen_rtx_fmt_");
182169689Skan      for (i = 0; i < XVECLEN (x, 1); i++)
183169689Skan	printf ("e");
184169689Skan      printf (" (GET_CODE (operand%d), ", XINT (x, 0));
18550397Sobrien      if (GET_MODE (x) == VOIDmode)
18650397Sobrien	printf ("GET_MODE (operand%d)", XINT (x, 0));
18750397Sobrien      else
18850397Sobrien	printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
18918334Speter      for (i = 0; i < XVECLEN (x, 1); i++)
19018334Speter	{
19118334Speter	  printf (",\n\t\t");
19296263Sobrien	  gen_exp (XVECEXP (x, 1, i), subroutine_type, used);
19318334Speter	}
19418334Speter      printf (")");
19518334Speter      return;
19618334Speter
19718334Speter    case MATCH_OPERATOR:
198169689Skan      printf ("gen_rtx_fmt_");
199169689Skan      for (i = 0; i < XVECLEN (x, 2); i++)
200169689Skan	printf ("e");
201169689Skan      printf (" (GET_CODE (operand%d)", XINT (x, 0));
20218334Speter      printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
20318334Speter      for (i = 0; i < XVECLEN (x, 2); i++)
20418334Speter	{
20518334Speter	  printf (",\n\t\t");
20696263Sobrien	  gen_exp (XVECEXP (x, 2, i), subroutine_type, used);
20718334Speter	}
20818334Speter      printf (")");
20918334Speter      return;
21018334Speter
21118334Speter    case MATCH_PARALLEL:
21218334Speter    case MATCH_PAR_DUP:
21318334Speter      printf ("operand%d", XINT (x, 0));
21418334Speter      return;
21518334Speter
21618334Speter    case MATCH_SCRATCH:
21790075Sobrien      gen_rtx_scratch (x, subroutine_type);
21818334Speter      return;
21918334Speter
22018334Speter    case ADDRESS:
22118334Speter      fatal ("ADDRESS expression code used in named instruction pattern");
22218334Speter
22318334Speter    case PC:
22418334Speter      printf ("pc_rtx");
22518334Speter      return;
226169689Skan    case CLOBBER:
227169689Skan      if (REG_P (XEXP (x, 0)))
228169689Skan	{
229169689Skan	  printf ("gen_hard_reg_clobber (%smode, %i)", GET_MODE_NAME (GET_MODE (XEXP (x, 0))),
230169689Skan			  			     REGNO (XEXP (x, 0)));
231169689Skan	  return;
232169689Skan	}
233169689Skan      break;
23418334Speter
23518334Speter    case CC0:
23618334Speter      printf ("cc0_rtx");
23718334Speter      return;
23818334Speter
23918334Speter    case CONST_INT:
24018334Speter      if (INTVAL (x) == 0)
24118334Speter	printf ("const0_rtx");
24218334Speter      else if (INTVAL (x) == 1)
24318334Speter	printf ("const1_rtx");
24418334Speter      else if (INTVAL (x) == -1)
24518334Speter	printf ("constm1_rtx");
246169689Skan      else if (-MAX_SAVED_CONST_INT <= INTVAL (x)
247169689Skan	  && INTVAL (x) <= MAX_SAVED_CONST_INT)
248169689Skan	printf ("const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
249169689Skan		(int) INTVAL (x));
25018334Speter      else if (INTVAL (x) == STORE_FLAG_VALUE)
25118334Speter	printf ("const_true_rtx");
25218334Speter      else
25350397Sobrien	{
25450397Sobrien	  printf ("GEN_INT (");
255117395Skan	  printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));
25650397Sobrien	  printf (")");
25750397Sobrien	}
25818334Speter      return;
25918334Speter
26018334Speter    case CONST_DOUBLE:
26118334Speter      /* These shouldn't be written in MD files.  Instead, the appropriate
26218334Speter	 routines in varasm.c should be called.  */
263169689Skan      gcc_unreachable ();
26450397Sobrien
26550397Sobrien    default:
26650397Sobrien      break;
26718334Speter    }
26818334Speter
26950397Sobrien  printf ("gen_rtx_");
27018334Speter  print_code (code);
27150397Sobrien  printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));
27218334Speter
27318334Speter  fmt = GET_RTX_FORMAT (code);
27418334Speter  len = GET_RTX_LENGTH (code);
27518334Speter  for (i = 0; i < len; i++)
27618334Speter    {
27718334Speter      if (fmt[i] == '0')
27818334Speter	break;
27918334Speter      printf (",\n\t");
280169689Skan      switch (fmt[i])
28118334Speter	{
282169689Skan	case 'e': case 'u':
283169689Skan	  gen_exp (XEXP (x, i), subroutine_type, used);
284169689Skan	  break;
285169689Skan
286169689Skan	case 'i':
287169689Skan	  printf ("%u", XINT (x, i));
288169689Skan	  break;
289169689Skan
290169689Skan	case 's':
291169689Skan	  printf ("\"%s\"", XSTR (x, i));
292169689Skan	  break;
293169689Skan
294169689Skan	case 'E':
295169689Skan	  {
296169689Skan	    int j;
297169689Skan	    printf ("gen_rtvec (%d", XVECLEN (x, i));
298169689Skan	    for (j = 0; j < XVECLEN (x, i); j++)
299169689Skan	      {
300169689Skan		printf (",\n\t\t");
301169689Skan		gen_exp (XVECEXP (x, i, j), subroutine_type, used);
302169689Skan	      }
303169689Skan	    printf (")");
304169689Skan	    break;
305169689Skan	  }
306169689Skan
307169689Skan	default:
308169689Skan	  gcc_unreachable ();
30918334Speter	}
31018334Speter    }
31118334Speter  printf (")");
312132718Skan}
31318334Speter
31418334Speter/* Generate the `gen_...' function for a DEFINE_INSN.  */
31518334Speter
31618334Speterstatic void
317132718Skangen_insn (rtx insn, int lineno)
31818334Speter{
31918334Speter  int operands;
32090075Sobrien  int i;
32118334Speter
32218334Speter  /* See if the pattern for this insn ends with a group of CLOBBERs of (hard)
32318334Speter     registers or MATCH_SCRATCHes.  If so, store away the information for
32450397Sobrien     later.  */
32518334Speter
32618334Speter  if (XVEC (insn, 1))
32718334Speter    {
32890075Sobrien      int has_hard_reg = 0;
32990075Sobrien
33018334Speter      for (i = XVECLEN (insn, 1) - 1; i > 0; i--)
33190075Sobrien	{
33290075Sobrien	  if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER)
33390075Sobrien	    break;
33418334Speter
335169689Skan	  if (REG_P (XEXP (XVECEXP (insn, 1, i), 0)))
33690075Sobrien	    has_hard_reg = 1;
33790075Sobrien	  else if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH)
33890075Sobrien	    break;
33990075Sobrien	}
34090075Sobrien
34118334Speter      if (i != XVECLEN (insn, 1) - 1)
34218334Speter	{
34390075Sobrien	  struct clobber_pat *p;
344169689Skan	  struct clobber_ent *link = XNEW (struct clobber_ent);
34590075Sobrien	  int j;
34618334Speter
34718334Speter	  link->code_number = insn_code_number;
34818334Speter
34918334Speter	  /* See if any previous CLOBBER_LIST entry is the same as this
35018334Speter	     one.  */
35118334Speter
35218334Speter	  for (p = clobber_list; p; p = p->next)
35318334Speter	    {
35418334Speter	      if (p->first_clobber != i + 1
35518334Speter		  || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1))
35618334Speter		continue;
35718334Speter
35818334Speter	      for (j = i + 1; j < XVECLEN (insn, 1); j++)
35918334Speter		{
36018334Speter		  rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0);
36118334Speter		  rtx new = XEXP (XVECEXP (insn, 1, j), 0);
36218334Speter
36318334Speter		  /* OLD and NEW are the same if both are to be a SCRATCH
364132718Skan		     of the same mode,
36518334Speter		     or if both are registers of the same mode and number.  */
36618334Speter		  if (! (GET_MODE (old) == GET_MODE (new)
36718334Speter			 && ((GET_CODE (old) == MATCH_SCRATCH
36818334Speter			      && GET_CODE (new) == MATCH_SCRATCH)
369169689Skan			     || (REG_P (old) && REG_P (new)
37018334Speter				 && REGNO (old) == REGNO (new)))))
37118334Speter		    break;
37218334Speter		}
373132718Skan
37418334Speter	      if (j == XVECLEN (insn, 1))
37518334Speter		break;
37618334Speter	    }
37718334Speter
37818334Speter	  if (p == 0)
37918334Speter	    {
380169689Skan	      p = XNEW (struct clobber_pat);
381132718Skan
38218334Speter	      p->insns = 0;
38318334Speter	      p->pattern = insn;
38418334Speter	      p->first_clobber = i + 1;
38518334Speter	      p->next = clobber_list;
38690075Sobrien	      p->has_hard_reg = has_hard_reg;
38718334Speter	      clobber_list = p;
38818334Speter	    }
38918334Speter
39018334Speter	  link->next = p->insns;
39118334Speter	  p->insns = link;
39218334Speter	}
39318334Speter    }
39418334Speter
39518334Speter  /* Don't mention instructions whose names are the null string
39618334Speter     or begin with '*'.  They are in the machine description just
39718334Speter     to be recognized.  */
39818334Speter  if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
39918334Speter    return;
40018334Speter
401117395Skan  printf ("/* %s:%d */\n", read_rtx_filename, lineno);
402117395Skan
403132718Skan  /* Find out how many operands this function has.  */
40418334Speter  operands = max_operand_vec (insn, 1);
40518334Speter  if (max_dup_opno >= operands)
40618334Speter    fatal ("match_dup operand number has no match_operand");
40718334Speter
40818334Speter  /* Output the function name and argument declarations.  */
40918334Speter  printf ("rtx\ngen_%s (", XSTR (insn, 0));
410132718Skan  if (operands)
411132718Skan    for (i = 0; i < operands; i++)
412132718Skan      if (i)
413132718Skan	printf (",\n\trtx operand%d ATTRIBUTE_UNUSED", i);
414132718Skan      else
415132718Skan	printf ("rtx operand%d ATTRIBUTE_UNUSED", i);
416132718Skan  else
417132718Skan    printf ("void");
41818334Speter  printf (")\n");
41918334Speter  printf ("{\n");
42018334Speter
421132718Skan  /* Output code to construct and return the rtl for the instruction body.  */
42218334Speter
42318334Speter  if (XVECLEN (insn, 1) == 1)
42418334Speter    {
42518334Speter      printf ("  return ");
42696263Sobrien      gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN, NULL);
42718334Speter      printf (";\n}\n\n");
42818334Speter    }
42918334Speter  else
43018334Speter    {
43190075Sobrien      printf ("  return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d",
43290075Sobrien	      XVECLEN (insn, 1));
43390075Sobrien
43418334Speter      for (i = 0; i < XVECLEN (insn, 1); i++)
43518334Speter	{
43618334Speter	  printf (",\n\t\t");
43796263Sobrien	  gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN, NULL);
43818334Speter	}
43918334Speter      printf ("));\n}\n\n");
44018334Speter    }
44118334Speter}
44218334Speter
44318334Speter/* Generate the `gen_...' function for a DEFINE_EXPAND.  */
44418334Speter
44518334Speterstatic void
446132718Skangen_expand (rtx expand)
44718334Speter{
44818334Speter  int operands;
44990075Sobrien  int i;
45018334Speter
45118334Speter  if (strlen (XSTR (expand, 0)) == 0)
45218334Speter    fatal ("define_expand lacks a name");
45318334Speter  if (XVEC (expand, 1) == 0)
45418334Speter    fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0));
45518334Speter
456132718Skan  /* Find out how many operands this function has.  */
45718334Speter  operands = max_operand_vec (expand, 1);
45818334Speter
45918334Speter  /* Output the function name and argument declarations.  */
46018334Speter  printf ("rtx\ngen_%s (", XSTR (expand, 0));
461132718Skan  if (operands)
462132718Skan    for (i = 0; i < operands; i++)
463132718Skan      if (i)
464132718Skan	printf (",\n\trtx operand%d", i);
465132718Skan      else
466132718Skan	printf ("rtx operand%d", i);
467132718Skan  else
468132718Skan    printf ("void");
46918334Speter  printf (")\n");
47018334Speter  printf ("{\n");
47118334Speter
47218334Speter  /* If we don't have any C code to write, only one insn is being written,
47318334Speter     and no MATCH_DUPs are present, we can just return the desired insn
47418334Speter     like we do for a DEFINE_INSN.  This saves memory.  */
47518334Speter  if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0')
47618334Speter      && operands > max_dup_opno
47718334Speter      && XVECLEN (expand, 1) == 1)
47818334Speter    {
47918334Speter      printf ("  return ");
48096263Sobrien      gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL);
48118334Speter      printf (";\n}\n\n");
48218334Speter      return;
48318334Speter    }
48418334Speter
48518334Speter  /* For each operand referred to only with MATCH_DUPs,
48618334Speter     make a local variable.  */
48718334Speter  for (i = operands; i <= max_dup_opno; i++)
48818334Speter    printf ("  rtx operand%d;\n", i);
48990075Sobrien  for (; i <= max_scratch_opno; i++)
49090075Sobrien    printf ("  rtx operand%d ATTRIBUTE_UNUSED;\n", i);
49118334Speter  printf ("  rtx _val = 0;\n");
49218334Speter  printf ("  start_sequence ();\n");
49318334Speter
49418334Speter  /* The fourth operand of DEFINE_EXPAND is some code to be executed
49518334Speter     before the actual construction.
49618334Speter     This code expects to refer to `operands'
49718334Speter     just as the output-code in a DEFINE_INSN does,
49818334Speter     but here `operands' is an automatic array.
49918334Speter     So copy the operand values there before executing it.  */
50018334Speter  if (XSTR (expand, 3) && *XSTR (expand, 3))
50118334Speter    {
50290075Sobrien      printf ("  {\n");
50390075Sobrien      if (operands > 0 || max_dup_opno >= 0 || max_scratch_opno >= 0)
50490075Sobrien	printf ("    rtx operands[%d];\n",
50590075Sobrien	    MAX (operands, MAX (max_scratch_opno, max_dup_opno) + 1));
50618334Speter      /* Output code to copy the arguments into `operands'.  */
50718334Speter      for (i = 0; i < operands; i++)
50890075Sobrien	printf ("    operands[%d] = operand%d;\n", i, i);
50918334Speter
51018334Speter      /* Output the special code to be executed before the sequence
51118334Speter	 is generated.  */
512169689Skan      print_rtx_ptr_loc (XSTR (expand, 3));
51318334Speter      printf ("%s\n", XSTR (expand, 3));
51418334Speter
51518334Speter      /* Output code to copy the arguments back out of `operands'
51618334Speter	 (unless we aren't going to use them at all).  */
51718334Speter      if (XVEC (expand, 1) != 0)
51818334Speter	{
51918334Speter	  for (i = 0; i < operands; i++)
52090075Sobrien	    printf ("    operand%d = operands[%d];\n", i, i);
52118334Speter	  for (; i <= max_dup_opno; i++)
52290075Sobrien	    printf ("    operand%d = operands[%d];\n", i, i);
52390075Sobrien	  for (; i <= max_scratch_opno; i++)
52490075Sobrien	    printf ("    operand%d = operands[%d];\n", i, i);
52518334Speter	}
52690075Sobrien      printf ("  }\n");
52718334Speter    }
52818334Speter
52918334Speter  /* Output code to construct the rtl for the instruction bodies.
53018334Speter     Use emit_insn to add them to the sequence being accumulated.
53118334Speter     But don't do this if the user's code has set `no_more' nonzero.  */
53218334Speter
53318334Speter  for (i = 0; i < XVECLEN (expand, 1); i++)
53418334Speter    {
53518334Speter      rtx next = XVECEXP (expand, 1, i);
53618334Speter      if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC)
53718334Speter	  || (GET_CODE (next) == PARALLEL
538117395Skan	      && ((GET_CODE (XVECEXP (next, 0, 0)) == SET
539117395Skan		   && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC)
540117395Skan		  || GET_CODE (XVECEXP (next, 0, 0)) == RETURN))
54118334Speter	  || GET_CODE (next) == RETURN)
54218334Speter	printf ("  emit_jump_insn (");
54318334Speter      else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL)
54418334Speter	       || GET_CODE (next) == CALL
54518334Speter	       || (GET_CODE (next) == PARALLEL
54618334Speter		   && GET_CODE (XVECEXP (next, 0, 0)) == SET
54718334Speter		   && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL)
54818334Speter	       || (GET_CODE (next) == PARALLEL
54918334Speter		   && GET_CODE (XVECEXP (next, 0, 0)) == CALL))
55018334Speter	printf ("  emit_call_insn (");
551169689Skan      else if (LABEL_P (next))
55218334Speter	printf ("  emit_label (");
55318334Speter      else if (GET_CODE (next) == MATCH_OPERAND
55490075Sobrien	       || GET_CODE (next) == MATCH_DUP
55518334Speter	       || GET_CODE (next) == MATCH_OPERATOR
55690075Sobrien	       || GET_CODE (next) == MATCH_OP_DUP
55718334Speter	       || GET_CODE (next) == MATCH_PARALLEL
55890075Sobrien	       || GET_CODE (next) == MATCH_PAR_DUP
55918334Speter	       || GET_CODE (next) == PARALLEL)
56018334Speter	printf ("  emit (");
56118334Speter      else
56218334Speter	printf ("  emit_insn (");
56396263Sobrien      gen_exp (next, DEFINE_EXPAND, NULL);
56418334Speter      printf (");\n");
56518334Speter      if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
56618334Speter	  && GET_CODE (SET_SRC (next)) == LABEL_REF)
56718334Speter	printf ("  emit_barrier ();");
56818334Speter    }
56918334Speter
570117395Skan  /* Call `get_insns' to extract the list of all the
57118334Speter     insns emitted within this gen_... function.  */
57218334Speter
573117395Skan  printf ("  _val = get_insns ();\n");
57418334Speter  printf ("  end_sequence ();\n");
57518334Speter  printf ("  return _val;\n}\n\n");
57618334Speter}
57718334Speter
578117395Skan/* Like gen_expand, but generates insns resulting from splitting SPLIT.  */
57950397Sobrien
58018334Speterstatic void
581132718Skangen_split (rtx split)
58218334Speter{
58390075Sobrien  int i;
58418334Speter  int operands;
58590075Sobrien  const char *const name =
58690075Sobrien    ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split");
58790075Sobrien  const char *unused;
58896263Sobrien  char *used;
58918334Speter
59018334Speter  if (XVEC (split, 0) == 0)
59190075Sobrien    fatal ("define_%s (definition %d) lacks a pattern", name,
59290075Sobrien	   insn_index_number);
59318334Speter  else if (XVEC (split, 2) == 0)
59490075Sobrien    fatal ("define_%s (definition %d) lacks a replacement pattern", name,
59518334Speter	   insn_index_number);
59618334Speter
59718334Speter  /* Find out how many operands this function has.  */
59818334Speter
59918334Speter  max_operand_vec (split, 2);
60090075Sobrien  operands = MAX (max_opno, MAX (max_dup_opno, max_scratch_opno)) + 1;
60190075Sobrien  unused = (operands == 0 ? " ATTRIBUTE_UNUSED" : "");
602169689Skan  used = XCNEWVEC (char, operands);
60318334Speter
60490075Sobrien  /* Output the prototype, function name and argument declarations.  */
60590075Sobrien  if (GET_CODE (split) == DEFINE_PEEPHOLE2)
60690075Sobrien    {
607132718Skan      printf ("extern rtx gen_%s_%d (rtx, rtx *);\n",
60890075Sobrien	      name, insn_code_number);
609132718Skan      printf ("rtx\ngen_%s_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n",
610132718Skan	      name, insn_code_number, unused);
61190075Sobrien    }
61290075Sobrien  else
61390075Sobrien    {
614169689Skan      printf ("extern rtx gen_split_%d (rtx, rtx *);\n", insn_code_number);
615169689Skan      printf ("rtx\ngen_split_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n",
616169689Skan	      insn_code_number, unused);
61790075Sobrien    }
61818334Speter  printf ("{\n");
61918334Speter
62018334Speter  /* Declare all local variables.  */
62118334Speter  for (i = 0; i < operands; i++)
62218334Speter    printf ("  rtx operand%d;\n", i);
62318334Speter  printf ("  rtx _val = 0;\n");
62490075Sobrien
62590075Sobrien  if (GET_CODE (split) == DEFINE_PEEPHOLE2)
62690075Sobrien    output_peephole2_scratches (split);
62790075Sobrien
62818334Speter  printf ("  start_sequence ();\n");
62918334Speter
63018334Speter  /* The fourth operand of DEFINE_SPLIT is some code to be executed
63118334Speter     before the actual construction.  */
63218334Speter
63318334Speter  if (XSTR (split, 3))
634169689Skan    {
635169689Skan      print_rtx_ptr_loc (XSTR (split, 3));
636169689Skan      printf ("%s\n", XSTR (split, 3));
637169689Skan    }
63818334Speter
63918334Speter  /* Output code to copy the arguments back out of `operands'  */
64018334Speter  for (i = 0; i < operands; i++)
64118334Speter    printf ("  operand%d = operands[%d];\n", i, i);
64218334Speter
64318334Speter  /* Output code to construct the rtl for the instruction bodies.
64418334Speter     Use emit_insn to add them to the sequence being accumulated.
64518334Speter     But don't do this if the user's code has set `no_more' nonzero.  */
64618334Speter
64718334Speter  for (i = 0; i < XVECLEN (split, 2); i++)
64818334Speter    {
64918334Speter      rtx next = XVECEXP (split, 2, i);
65018334Speter      if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC)
65118334Speter	  || (GET_CODE (next) == PARALLEL
65218334Speter	      && GET_CODE (XVECEXP (next, 0, 0)) == SET
65318334Speter	      && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC)
65418334Speter	  || GET_CODE (next) == RETURN)
65518334Speter	printf ("  emit_jump_insn (");
65618334Speter      else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL)
65718334Speter	       || GET_CODE (next) == CALL
65818334Speter	       || (GET_CODE (next) == PARALLEL
65918334Speter		   && GET_CODE (XVECEXP (next, 0, 0)) == SET
66018334Speter		   && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL)
66118334Speter	       || (GET_CODE (next) == PARALLEL
66218334Speter		   && GET_CODE (XVECEXP (next, 0, 0)) == CALL))
66318334Speter	printf ("  emit_call_insn (");
664169689Skan      else if (LABEL_P (next))
66518334Speter	printf ("  emit_label (");
66618334Speter      else if (GET_CODE (next) == MATCH_OPERAND
66718334Speter	       || GET_CODE (next) == MATCH_OPERATOR
66818334Speter	       || GET_CODE (next) == MATCH_PARALLEL
66918334Speter	       || GET_CODE (next) == MATCH_OP_DUP
67018334Speter	       || GET_CODE (next) == MATCH_DUP
67118334Speter	       || GET_CODE (next) == PARALLEL)
67218334Speter	printf ("  emit (");
67318334Speter      else
67418334Speter	printf ("  emit_insn (");
67596263Sobrien      gen_exp (next, GET_CODE (split), used);
67618334Speter      printf (");\n");
67718334Speter      if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
67818334Speter	  && GET_CODE (SET_SRC (next)) == LABEL_REF)
67918334Speter	printf ("  emit_barrier ();");
68018334Speter    }
68118334Speter
682117395Skan  /* Call `get_insns' to make a list of all the
68318334Speter     insns emitted within this gen_... function.  */
68418334Speter
685117395Skan  printf ("  _val = get_insns ();\n");
68618334Speter  printf ("  end_sequence ();\n");
68718334Speter  printf ("  return _val;\n}\n\n");
68896263Sobrien
68996263Sobrien  free (used);
69018334Speter}
69118334Speter
69218334Speter/* Write a function, `add_clobbers', that is given a PARALLEL of sufficient
69318334Speter   size for the insn and an INSN_CODE, and inserts the required CLOBBERs at
69418334Speter   the end of the vector.  */
69518334Speter
69618334Speterstatic void
697132718Skanoutput_add_clobbers (void)
69818334Speter{
69918334Speter  struct clobber_pat *clobber;
70018334Speter  struct clobber_ent *ent;
70118334Speter  int i;
70218334Speter
703132718Skan  printf ("\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n");
70418334Speter  printf ("{\n");
70518334Speter  printf ("  switch (insn_code_number)\n");
70618334Speter  printf ("    {\n");
70718334Speter
70818334Speter  for (clobber = clobber_list; clobber; clobber = clobber->next)
70918334Speter    {
71018334Speter      for (ent = clobber->insns; ent; ent = ent->next)
71118334Speter	printf ("    case %d:\n", ent->code_number);
71218334Speter
71318334Speter      for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
71418334Speter	{
71518334Speter	  printf ("      XVECEXP (pattern, 0, %d) = ", i);
71690075Sobrien	  gen_exp (XVECEXP (clobber->pattern, 1, i),
71796263Sobrien		   GET_CODE (clobber->pattern), NULL);
71818334Speter	  printf (";\n");
71918334Speter	}
72018334Speter
72118334Speter      printf ("      break;\n\n");
72218334Speter    }
72318334Speter
72418334Speter  printf ("    default:\n");
725169689Skan  printf ("      gcc_unreachable ();\n");
72618334Speter  printf ("    }\n");
72718334Speter  printf ("}\n");
72818334Speter}
72918334Speter
730169689Skan/* Write a function, `added_clobbers_hard_reg_p' that is given an insn_code
731169689Skan   number that will have clobbers added (as indicated by `recog') and returns
732169689Skan   1 if those include a clobber of a hard reg or 0 if all of them just clobber
733169689Skan   SCRATCH.  */
73418334Speter
73518334Speterstatic void
736132718Skanoutput_added_clobbers_hard_reg_p (void)
73718334Speter{
73890075Sobrien  struct clobber_pat *clobber;
73990075Sobrien  struct clobber_ent *ent;
74096263Sobrien  int clobber_p, used;
74118334Speter
742132718Skan  printf ("\n\nint\nadded_clobbers_hard_reg_p (int insn_code_number)\n");
74390075Sobrien  printf ("{\n");
74490075Sobrien  printf ("  switch (insn_code_number)\n");
74590075Sobrien  printf ("    {\n");
74618334Speter
74790075Sobrien  for (clobber_p = 0; clobber_p <= 1; clobber_p++)
74818334Speter    {
74996263Sobrien      used = 0;
75090075Sobrien      for (clobber = clobber_list; clobber; clobber = clobber->next)
75190075Sobrien	if (clobber->has_hard_reg == clobber_p)
75290075Sobrien	  for (ent = clobber->insns; ent; ent = ent->next)
75396263Sobrien	    {
75496263Sobrien	      printf ("    case %d:\n", ent->code_number);
75596263Sobrien	      used++;
75696263Sobrien	    }
75790075Sobrien
75896263Sobrien      if (used)
75996263Sobrien	printf ("      return %d;\n\n", clobber_p);
76018334Speter    }
76118334Speter
76290075Sobrien  printf ("    default:\n");
763169689Skan  printf ("      gcc_unreachable ();\n");
76490075Sobrien  printf ("    }\n");
76518334Speter  printf ("}\n");
76618334Speter}
76718334Speter
76890075Sobrien/* Generate code to invoke find_free_register () as needed for the
76990075Sobrien   scratch registers used by the peephole2 pattern in SPLIT.  */
77018334Speter
77190075Sobrienstatic void
772132718Skanoutput_peephole2_scratches (rtx split)
77318334Speter{
77490075Sobrien  int i;
77590075Sobrien  int insn_nr = 0;
77618334Speter
77790075Sobrien  printf ("  HARD_REG_SET _regs_allocated;\n");
77890075Sobrien  printf ("  CLEAR_HARD_REG_SET (_regs_allocated);\n");
77950397Sobrien
78090075Sobrien  for (i = 0; i < XVECLEN (split, 0); i++)
78190075Sobrien    {
78290075Sobrien      rtx elt = XVECEXP (split, 0, i);
78390075Sobrien      if (GET_CODE (elt) == MATCH_SCRATCH)
78490075Sobrien	{
78590075Sobrien	  int last_insn_nr = insn_nr;
78690075Sobrien	  int cur_insn_nr = insn_nr;
78790075Sobrien	  int j;
78890075Sobrien	  for (j = i + 1; j < XVECLEN (split, 0); j++)
78990075Sobrien	    if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP)
79090075Sobrien	      {
79190075Sobrien		if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0))
79290075Sobrien		  last_insn_nr = cur_insn_nr;
79390075Sobrien	      }
79490075Sobrien	    else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH)
79590075Sobrien	      cur_insn_nr++;
79650397Sobrien
79790075Sobrien	  printf ("  if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
798132718Skan    return NULL;\n",
79990075Sobrien		  XINT (elt, 0),
80090075Sobrien		  insn_nr, last_insn_nr,
80190075Sobrien		  XSTR (elt, 1),
80290075Sobrien		  GET_MODE_NAME (GET_MODE (elt)));
80350397Sobrien
80490075Sobrien	}
80590075Sobrien      else if (GET_CODE (elt) != MATCH_DUP)
80690075Sobrien	insn_nr++;
80790075Sobrien    }
80818334Speter}
80918334Speter
81018334Speterint
811132718Skanmain (int argc, char **argv)
81218334Speter{
81318334Speter  rtx desc;
81418334Speter
81590075Sobrien  progname = "genemit";
81618334Speter
81790075Sobrien  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
81890075Sobrien    return (FATAL_EXIT_CODE);
81918334Speter
82018334Speter  /* Assign sequential codes to all entries in the machine description
82118334Speter     in parallel with the tables in insn-output.c.  */
82218334Speter
82318334Speter  insn_code_number = 0;
82418334Speter  insn_index_number = 0;
82518334Speter
82618334Speter  printf ("/* Generated automatically by the program `genemit'\n\
82718334Speterfrom the machine description file `md'.  */\n\n");
82818334Speter
82918334Speter  printf ("#include \"config.h\"\n");
83050397Sobrien  printf ("#include \"system.h\"\n");
831132718Skan  printf ("#include \"coretypes.h\"\n");
832132718Skan  printf ("#include \"tm.h\"\n");
83318334Speter  printf ("#include \"rtl.h\"\n");
83490075Sobrien  printf ("#include \"tm_p.h\"\n");
83590075Sobrien  printf ("#include \"function.h\"\n");
83618334Speter  printf ("#include \"expr.h\"\n");
83790075Sobrien  printf ("#include \"optabs.h\"\n");
83818334Speter  printf ("#include \"real.h\"\n");
83950397Sobrien  printf ("#include \"flags.h\"\n");
84018334Speter  printf ("#include \"output.h\"\n");
84152284Sobrien  printf ("#include \"insn-config.h\"\n");
84290075Sobrien  printf ("#include \"hard-reg-set.h\"\n");
84352284Sobrien  printf ("#include \"recog.h\"\n");
84490075Sobrien  printf ("#include \"resource.h\"\n");
84590075Sobrien  printf ("#include \"reload.h\"\n");
84690075Sobrien  printf ("#include \"toplev.h\"\n");
847169689Skan  printf ("#include \"tm-constrs.h\"\n");
84890075Sobrien  printf ("#include \"ggc.h\"\n\n");
849169689Skan  printf ("#include \"basic-block.h\"\n\n");
85052284Sobrien  printf ("#define FAIL return (end_sequence (), _val)\n");
851117395Skan  printf ("#define DONE return (_val = get_insns (), end_sequence (), _val)\n\n");
85218334Speter
85318334Speter  /* Read the machine description.  */
85418334Speter
85518334Speter  while (1)
85618334Speter    {
85790075Sobrien      int line_no;
85890075Sobrien
85990075Sobrien      desc = read_md_rtx (&line_no, &insn_code_number);
86090075Sobrien      if (desc == NULL)
86118334Speter	break;
86218334Speter
86390075Sobrien      switch (GET_CODE (desc))
86418334Speter	{
865117395Skan	case DEFINE_INSN:
866117395Skan	  gen_insn (desc, line_no);
867117395Skan	  break;
86890075Sobrien
869117395Skan	case DEFINE_EXPAND:
870117395Skan	  printf ("/* %s:%d */\n", read_rtx_filename, line_no);
871117395Skan	  gen_expand (desc);
872117395Skan	  break;
87390075Sobrien
874117395Skan	case DEFINE_SPLIT:
875117395Skan	  printf ("/* %s:%d */\n", read_rtx_filename, line_no);
876117395Skan	  gen_split (desc);
877117395Skan	  break;
87890075Sobrien
879117395Skan	case DEFINE_PEEPHOLE2:
880117395Skan	  printf ("/* %s:%d */\n", read_rtx_filename, line_no);
881117395Skan	  gen_split (desc);
882117395Skan	  break;
88390075Sobrien
884117395Skan	default:
885117395Skan	  break;
886117395Skan	}
88718334Speter      ++insn_index_number;
88818334Speter    }
88918334Speter
89090075Sobrien  /* Write out the routines to add CLOBBERs to a pattern and say whether they
89190075Sobrien     clobber a hard reg.  */
89218334Speter  output_add_clobbers ();
89390075Sobrien  output_added_clobbers_hard_reg_p ();
89418334Speter
89518334Speter  fflush (stdout);
89690075Sobrien  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
89718334Speter}
898