/* Generate code from machine description to emit insns as rtl.
- Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91, 94, 95, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
-#include <stdio.h>
-#include "config.h"
+#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
static int max_opno;
static int max_dup_opno;
struct clobber_pat
{
- int code_number; /* Counts only insns. */
+ struct clobber_ent *insns;
rtx pattern;
int first_clobber;
struct clobber_pat *next;
} *clobber_list;
+/* Records one insn that uses the clobber list. */
+
+struct clobber_ent
+{
+ int code_number; /* Counts only insns. */
+ struct clobber_ent *next;
+};
+
+static void max_operand_1 PROTO((rtx));
+static int max_operand_vec PROTO((rtx, int));
+static void print_code PROTO((RTX_CODE));
+static void gen_exp PROTO((rtx));
+static void gen_insn PROTO((rtx));
+static void gen_expand PROTO((rtx));
+static void gen_split PROTO((rtx));
+static void output_add_clobbers PROTO((void));
+static void output_init_mov_optab PROTO((void));
+
+\f
static void
max_operand_1 (x)
rtx x;
if (code == MATCH_OPERAND || code == MATCH_OPERATOR
|| code == MATCH_PARALLEL)
max_opno = MAX (max_opno, XINT (x, 0));
- if (code == MATCH_DUP || code == MATCH_OP_DUP)
+ if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)
max_dup_opno = MAX (max_dup_opno, XINT (x, 0));
fmt = GET_RTX_FORMAT (code);
if (x == 0)
{
- printf ("0");
+ printf ("NULL_RTX");
return;
}
return;
case MATCH_OP_DUP:
- printf ("gen_rtx (GET_CODE (operand%d), GET_MODE (operand%d)",
- XINT (x, 0), XINT (x, 0));
+ printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0));
+ if (GET_MODE (x) == VOIDmode)
+ printf ("GET_MODE (operand%d)", XINT (x, 0));
+ else
+ printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
for (i = 0; i < XVECLEN (x, 1); i++)
{
printf (",\n\t\t");
return;
case MATCH_PARALLEL:
+ case MATCH_PAR_DUP:
printf ("operand%d", XINT (x, 0));
return;
case MATCH_SCRATCH:
- printf ("gen_rtx (SCRATCH, %smode, 0)", GET_MODE_NAME (GET_MODE (x)));
+ printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
return;
case ADDRESS:
case CONST_INT:
if (INTVAL (x) == 0)
+ printf ("const0_rtx");
+ else if (INTVAL (x) == 1)
+ printf ("const1_rtx");
+ else if (INTVAL (x) == -1)
+ printf ("constm1_rtx");
+ else if (INTVAL (x) == STORE_FLAG_VALUE)
+ printf ("const_true_rtx");
+ else
{
- printf ("const0_rtx");
- return;
- }
- if (INTVAL (x) == 1)
- {
- printf ("const1_rtx");
- return;
- }
- if (INTVAL (x) == -1)
- {
- printf ("constm1_rtx");
- return;
- }
- if (INTVAL (x) == STORE_FLAG_VALUE)
- {
- printf ("const_true_rtx");
- return;
+ printf ("GEN_INT (");
+ printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
+ printf (")");
}
+ return;
+
+ case CONST_DOUBLE:
+ /* These shouldn't be written in MD files. Instead, the appropriate
+ routines in varasm.c should be called. */
+ abort ();
+
+ default:
+ break;
}
- printf ("gen_rtx (");
+ printf ("gen_rtx_");
print_code (code);
- printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
+ printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));
fmt = GET_RTX_FORMAT (code);
len = GET_RTX_LENGTH (code);
{
if (fmt[i] == '0')
break;
- printf (", ");
+ printf (",\n\t");
if (fmt[i] == 'e' || fmt[i] == 'u')
gen_exp (XEXP (x, i));
else if (fmt[i] == 'i')
- printf ("%u", (unsigned) XINT (x, i));
+ printf ("%u", XINT (x, i));
else if (fmt[i] == 's')
printf ("\"%s\"", XSTR (x, i));
else if (fmt[i] == 'E')
/* See if the pattern for this insn ends with a group of CLOBBERs of (hard)
registers or MATCH_SCRATCHes. If so, store away the information for
- later. */
+ later. */
if (XVEC (insn, 1))
{
if (i != XVECLEN (insn, 1) - 1)
{
- register struct clobber_pat *new
- = (struct clobber_pat *) xmalloc (sizeof (struct clobber_pat));
+ register struct clobber_pat *p;
+ register struct clobber_ent *link
+ = (struct clobber_ent *) xmalloc (sizeof (struct clobber_ent));
+ register int j;
+
+ link->code_number = insn_code_number;
+
+ /* See if any previous CLOBBER_LIST entry is the same as this
+ one. */
+
+ for (p = clobber_list; p; p = p->next)
+ {
+ if (p->first_clobber != i + 1
+ || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1))
+ continue;
+
+ for (j = i + 1; j < XVECLEN (insn, 1); j++)
+ {
+ rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0);
+ rtx new = XEXP (XVECEXP (insn, 1, j), 0);
+
+ /* OLD and NEW are the same if both are to be a SCRATCH
+ of the same mode,
+ or if both are registers of the same mode and number. */
+ if (! (GET_MODE (old) == GET_MODE (new)
+ && ((GET_CODE (old) == MATCH_SCRATCH
+ && GET_CODE (new) == MATCH_SCRATCH)
+ || (GET_CODE (old) == REG && GET_CODE (new) == REG
+ && REGNO (old) == REGNO (new)))))
+ break;
+ }
+
+ if (j == XVECLEN (insn, 1))
+ break;
+ }
+
+ if (p == 0)
+ {
+ p = (struct clobber_pat *) xmalloc (sizeof (struct clobber_pat));
- new->code_number = insn_code_number;
- new->pattern = insn;
- new->first_clobber = i + 1;
- new->next = clobber_list;
- clobber_list = new;
+ p->insns = 0;
+ p->pattern = insn;
+ p->first_clobber = i + 1;
+ p->next = clobber_list;
+ clobber_list = p;
+ }
+
+ link->next = p->insns;
+ p->insns = link;
}
}
- /* Don't mention instructions whose names are the null string.
- They are in the machine description just to be recognized. */
- if (strlen (XSTR (insn, 0)) == 0)
+ /* Don't mention instructions whose names are the null string
+ or begin with '*'. They are in the machine description just
+ to be recognized. */
+ if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
return;
/* Find out how many operands this function has,
}
else
{
- printf (" return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1));
+ printf (" return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1));
for (i = 0; i < XVECLEN (insn, 1); i++)
{
printf (",\n\t\t");
/* Call `gen_sequence' to make a SEQUENCE out of all the
insns emitted within this gen_... function. */
- printf (" _done:\n");
printf (" _val = gen_sequence ();\n");
- printf (" _fail:\n");
printf (" end_sequence ();\n");
printf (" return _val;\n}\n\n");
}
/* Like gen_expand, but generates a SEQUENCE. */
+
static void
gen_split (split)
rtx split;
/* Declare all local variables. */
for (i = 0; i < operands; i++)
printf (" rtx operand%d;\n", i);
- printf (" rtx _val;\n");
+ printf (" rtx _val = 0;\n");
printf (" start_sequence ();\n");
/* The fourth operand of DEFINE_SPLIT is some code to be executed
/* Call `gen_sequence' to make a SEQUENCE out of all the
insns emitted within this gen_... function. */
- printf (" _done:\n");
printf (" _val = gen_sequence ();\n");
- printf (" _fail:\n");
printf (" end_sequence ();\n");
printf (" return _val;\n}\n\n");
}
output_add_clobbers ()
{
struct clobber_pat *clobber;
+ struct clobber_ent *ent;
int i;
printf ("\n\nvoid\nadd_clobbers (pattern, insn_code_number)\n");
printf (" rtx pattern;\n int insn_code_number;\n");
printf ("{\n");
- printf (" int i;\n\n");
printf (" switch (insn_code_number)\n");
printf (" {\n");
for (clobber = clobber_list; clobber; clobber = clobber->next)
{
- printf (" case %d:\n", clobber->code_number);
+ for (ent = clobber->insns; ent; ent = ent->next)
+ printf (" case %d:\n", ent->code_number);
for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
{
printf (";\n");
}
- printf (" break;\n");
+ printf (" break;\n\n");
}
printf (" default:\n");
#ifdef EXTRA_CC_NAMES
static char *cc_names[] = { EXTRA_CC_NAMES };
char *p;
- int i;
+ size_t i;
printf ("\nvoid\ninit_mov_optab ()\n{\n");
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genemit: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
{
rtx desc;
FILE *infile;
- extern rtx read_rtx ();
register int c;
obstack_init (rtl_obstack);
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"expr.h\"\n");
printf ("#include \"real.h\"\n");
+ printf ("#include \"flags.h\"\n");
printf ("#include \"output.h\"\n");
printf ("#include \"insn-config.h\"\n\n");
printf ("#include \"insn-flags.h\"\n\n");
printf ("extern char *insn_operand_constraint[][MAX_RECOG_OPERANDS];\n\n");
printf ("extern rtx recog_operand[];\n");
printf ("#define operands emit_operand\n\n");
- printf ("#define FAIL goto _fail\n\n");
- printf ("#define DONE goto _done\n\n");
+ printf ("#define FAIL do {end_sequence (); return _val;} while (0)\n");
+ printf ("#define DONE do {_val = gen_sequence (); end_sequence (); return _val;} while (0)\n");
/* Read the machine description. */