/
genemit.c
/
static void
max_operand_1 (x)
rtx x;
{
register RTX_CODE code;
register int i;
register int len;
register char fmt;
if (x == 0)
return;
code = GET_CODE (x);
if (code == MATCH_OPERAND && XSTR (x, 2) != 0 && XSTR (x, 2) != ‘ ’)
register_constraints = 1;
if (code == MATCH_SCRATCH && XSTR (x, 1) != 0 && XSTR (x, 1) != ‘ ’)
register_constraints = 1;
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 || code == MATCH_PAR_DUP)
max_dup_opno = MAX (max_dup_opno, XINT (x, 0));
fmt = GET_RTX_FORMAT (code);
len = GET_RTX_LENGTH (code);
for (i = 0; i < len; i++)
{
if (fmt[i] == ‘e’ || fmt[i] == ‘u’)
max_operand_1 (XEXP (x, i));
else if (fmt[i] == ‘E’)
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
max_operand_1 (XVECEXP (x, i, j));
}
}
}
static int
max_operand_vec (insn, arg)
rtx insn;
int arg;
{
register int len = XVECLEN (insn, arg);
register int i;
max_opno = -1;
max_dup_opno = -1;
for (i = 0; i < len; i++)
max_operand_1 (XVECEXP (insn, arg, i));
return max_opno + 1;
}
/ Print a C expression to construct an RTX just like X,
substituting any operand references appearing within. /
static void
gen_exp (x)
rtx x;
{
register RTX_CODE code;
register int i;
register int len;
register char fmt;
if (x == 0)
{
printf ("NULL_RTX");
return;
}
code = GET_CODE (x);
switch (code)
{
case MATCH_OPERAND:
case MATCH_DUP:
printf ("operand%d", XINT (x, 0));
return;
case MATCH_OP_DUP:
printf ("gen_rtx (GET_CODE (operand%d), GET_MODE (operand%d)",
XINT (x, 0), XINT (x, 0));
for (i = 0; i < XVECLEN (x, 1); i++)
{
printf (",ntt");
gen_exp (XVECEXP (x, 1, i));
}
printf (")");
return;
case MATCH_OPERATOR:
printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0));
printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
for (i = 0; i < XVECLEN (x, 2); i++)
{
printf (",ntt");
gen_exp (XVECEXP (x, 2, i));
}
printf (")");
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)));
return;
case ADDRESS:
fatal ("ADDRESS expression code used in named instruction pattern");
case PC:
printf ("pc_rtx");
return;
case CC0:
printf ("cc0_rtx");
return;
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 (
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
"GEN_INT (%d)",
#else
"GEN_INT (%ld)",
#endif
INTVAL (x));
return;
case CONST_DOUBLE:
/ These shouldn’t be written in MD files. Instead, the appropriate
routines in varasm.c should be called. /
abort ();
}
printf ("gen_rtx (");
print_code (code);
printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
fmt = GET_RTX_FORMAT (code);
len = GET_RTX_LENGTH (code);
for (i = 0; i < len; i++)
{
if (fmt[i] == ‘0’)
break;
printf (",nt");
if (fmt[i] == ‘e’ || fmt[i] == ‘u’)
gen_exp (XEXP (x, i));
else if (fmt[i] == ‘i’)
printf ("%u", XINT (x, i));
else if (fmt[i] == ‘s’)
printf (""%s"", XSTR (x, i));
else if (fmt[i] == ‘E’)
{
int j;
printf ("gen_rtvec (%d", XVECLEN (x, i));
for (j = 0; j < XVECLEN (x, i); j++)
{
printf (",ntt");
genexp (XVECEXP (x, i, j));
}
printf (")");
}
else
abort ();
}
printf (")");
}
/* Generate the `gen…’ function for a DEFINE_INSN. /
static void
gen_insn (insn)
rtx insn;
{
int operands;
register int i;
/ 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. /
if (XVEC (insn, 1))
{
for (i = XVECLEN (insn, 1) - 1; i > 0; i–)
if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER
|| (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != REG
&& GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH))
break;
if (i != XVECLEN (insn, 1) - 1)
{
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));
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
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,
and also whether any of them have register constraints. /
register_constraints = 0;
operands = max_operand_vec (insn, 1);
if (max_dup_opno >= operands)
fatal ("match_dup operand number has no match_operand");
/ Output the function name and argument declarations. /
printf ("rtxngen_%s (", XSTR (insn, 0));
for (i = 0; i < operands; i++)
printf (i ? ", operand%d" : "operand%d", i);
printf (")n");
for (i = 0; i < operands; i++)
printf (" rtx operand%d;n", i);
printf ("{n");
/ Output code to construct and return the rtl for the instruction body /
if (XVECLEN (insn, 1) == 1)
{
printf (" return ");
gen_exp (XVECEXP (insn, 1, 0));
printf (";n}nn");
}
else
{
printf (" return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1));
for (i = 0; i < XVECLEN (insn, 1); i++)
{
printf (",ntt");
gen_exp (XVECEXP (insn, 1, i));
}
printf ("));n}nn");
}
}
/ Generate the gen_...' function for a DEFINE_EXPAND. */<br /><br />static void<br />gen_expand (expand)<br /> rtx expand;<br />{<br />int operands;<br />register int i;<br /><br />if (strlen (XSTR (expand, 0)) == 0)<br /> fatal ("define_expand lacks a name");<br />if (XVEC (expand, 1) == 0)<br /> fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0));<br /><br />/* Find out how many operands this function has,<br /> and also whether any of them have register constraints. */<br />register_constraints = 0;<br /><br />operands = max_operand_vec (expand, 1);<br /><br />/* Output the function name and argument declarations. */<br />printf ("rtxngen_%s (", XSTR (expand, 0));<br />for (i = 0; i < operands; i++)<br /> printf (i ? ", operand%d" : "operand%d", i);<br />printf (")n");<br />for (i = 0; i < operands; i++)<br /> printf (" rtx operand%d;n", i);<br />printf ("{n");<br /><br />/* If we don't have any C code to write, only one insn is being written,<br /> and no MATCH_DUPs are present, we can just return the desired insn<br /> like we do for a DEFINE_INSN. This saves memory. */<br />if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '