/* Generate code from machine description to compute values of attributes.
- Copyright (C) 1991 Free Software Foundation, Inc.
- Contributed by Richard Kenner (kenner@nyu.edu)
+ Copyright (C) 1991, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
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. */
/* This program handles insn attributes and the DEFINE_DELAY and
DEFINE_FUNCTION_UNIT definitions.
EQ_ATTR rtx is true if !volatil and false if volatil. */
-#include "gvarargs.h"
#include "hconfig.h"
+/* varargs must always be included after *config.h. */
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
#include "rtl.h"
#include "insn-config.h" /* For REGISTER_CONSTRAINTS */
#include <stdio.h>
struct insn_def
{
- int insn_code; /* Instruction number. */
- int insn_index; /* Expression numer in file, for errors. */
- struct insn_def *next; /* Next insn in chain. */
- rtx def; /* The DEFINE_... */
+ int insn_code; /* Instruction number. */
+ int insn_index; /* Expression numer in file, for errors. */
+ struct insn_def *next; /* Next insn in chain. */
+ rtx def; /* The DEFINE_... */
int num_alternatives; /* Number of alternatives. */
- int vec_idx; /* Index of attribute vector in `def'. */
+ int vec_idx; /* Index of attribute vector in `def'. */
};
/* Once everything has been read in, we store in each attribute value a list
struct attr_desc
{
- char *name; /* Name of attribute. */
- struct attr_desc *next; /* Next attribute. */
- int is_numeric; /* Values of this attribute are numeric. */
+ char *name; /* Name of attribute. */
+ struct attr_desc *next; /* Next attribute. */
+ int is_numeric; /* Values of this attribute are numeric. */
int negative_ok; /* Allow negative numeric values. */
int unsigned_p; /* Make the output function unsigned int. */
int is_const; /* Attribute value constant for each run. */
- int is_special; /* Don't call `write_attr_set'. */
- struct attr_value *first_value; /* First value of this attribute. */
- struct attr_value *default_val; /* Default value for this attribute. */
+ int is_special; /* Don't call `write_attr_set'. */
+ struct attr_value *first_value; /* First value of this attribute. */
+ struct attr_value *default_val; /* Default value for this attribute. */
};
#define NULL_ATTR (struct attr_desc *) NULL
struct delay_desc
{
rtx def; /* DEFINE_DELAY expression. */
- struct delay_desc *next; /* Next DEFINE_DELAY. */
+ struct delay_desc *next; /* Next DEFINE_DELAY. */
int num; /* Number of DEFINE_DELAY, starting at 1. */
};
int multiplicity; /* Number of units of this type. */
int simultaneity; /* Maximum number of simultaneous insns
on this function unit or 0 if unlimited. */
- rtx condexp; /* Expression TRUE for insn needing unit. */
+ rtx condexp; /* Expression TRUE for insn needing unit. */
int num_opclasses; /* Number of different operation types. */
struct function_unit_op *ops; /* Pointer to first operation type. */
int needs_conflict_function; /* Nonzero if a conflict function required. */
int num_values; /* Length of the values list. */
};
-/* Other variables. */
+/* Other variables. */
static int insn_code_number;
static int insn_index_number;
static int num_delays;
static int have_annul_true, have_annul_false;
static int num_units;
+static int num_insn_ents;
/* Used as operand to `operate_exp': */
/* These are referenced by rtlanal.c and hence need to be defined somewhere.
They won't actually be used. */
-rtx frame_pointer_rtx, stack_pointer_rtx, arg_pointer_rtx;
+rtx frame_pointer_rtx, hard_frame_pointer_rtx, stack_pointer_rtx;
+rtx arg_pointer_rtx;
-#if 0
-static rtx attr_rtx PROTO((enum rtx_code, ...));
-static char *attr_printf PROTO((int, char *, ...));
+static rtx attr_rtx PVPROTO((enum rtx_code, ...));
+#ifdef HAVE_VPRINTF
+static char *attr_printf PVPROTO((int, char *, ...));
#else
-static rtx attr_rtx ();
static char *attr_printf ();
#endif
static rtx simplify_knowing PROTO((rtx, rtx));
static rtx encode_units_mask PROTO((rtx));
static void fill_attr PROTO((struct attr_desc *));
-static rtx substitute_address PROTO((rtx, rtx (*) (rtx), rtx (*) (rtx)));
+/* dpx2 compiler chokes if we specify the arg types of the args. */
+static rtx substitute_address PROTO((rtx, rtx (*) (), rtx (*) ()));
static void make_length_attrs PROTO((void));
static rtx identity_fn PROTO((rtx));
static rtx zero_fn PROTO((rtx));
static rtx test_for_current_value PROTO((struct dimension *, int));
static rtx simplify_with_current_value PROTO((rtx, struct dimension *, int));
static rtx simplify_with_current_value_aux PROTO((rtx));
+static void clear_struct_flag PROTO((rtx));
+static int count_sub_rtxs PROTO((rtx, int));
static void remove_insn_ent PROTO((struct attr_value *, struct insn_ent *));
static void insert_insn_ent PROTO((struct attr_value *, struct insn_ent *));
static rtx insert_right_side PROTO((enum rtx_code, rtx, rtx, int, int));
/*VARARGS1*/
static rtx
-attr_rtx (va_alist)
- va_dcl
+attr_rtx VPROTO((enum rtx_code code, ...))
{
- va_list p;
+#ifndef __STDC__
enum rtx_code code;
+#endif
+ va_list p;
register int i; /* Array indices... */
register char *fmt; /* Current rtx's format... */
register rtx rt_val; /* RTX to return to caller... */
register struct attr_hash *h;
struct obstack *old_obstack = rtl_obstack;
- va_start (p);
+ VA_START (p, code);
+
+#ifndef __STDC__
code = va_arg (p, enum rtx_code);
+#endif
/* For each of several cases, search the hash table for an existing entry.
Use that entry if one is found; otherwise create a new RTL and add it
/*VARARGS2*/
static char *
-attr_printf (va_alist)
- va_dcl
+attr_printf VPROTO((register int len, char *fmt, ...))
{
- va_list p;
+#ifndef __STDC__
register int len;
- register char *fmt;
+ char *fmt;
+#endif
+ va_list p;
register char *str;
- /* Print the string into a temporary location. */
- va_start (p);
+ VA_START (p, fmt);
+
+#ifndef __STDC__
len = va_arg (p, int);
- str = (char *) alloca (len);
fmt = va_arg (p, char *);
+#endif
+
+ /* Print the string into a temporary location. */
+ str = (char *) alloca (len);
vsprintf (str, fmt, p);
va_end (p);
}
break;
+ case ATTR_FLAG:
+ break;
+
case CONST_INT:
/* Either TRUE or FALSE. */
if (XWINT (exp, 0))
/* A constant SYMBOL_REF is valid as a constant attribute test and
is expanded later by make_canonical into a COND. */
return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
- /* Otherwise, fall through... */
+ /* Otherwise, fall through... */
default:
- fatal ("Illegal operation `%s' for attribute value",
+ fatal ("Invalid operation `%s' for attribute value",
GET_RTX_NAME (GET_CODE (exp)));
}
\f
/* Scan all definitions, checking for validity. Also, convert any SET_ATTR
and SET_ATTR_ALTERNATIVE expressions to the corresponding SET
- expressions. */
+ expressions. */
static void
check_defs ()
int allsame = 1;
rtx defval;
- /* First, check for degenerate COND. */
+ /* First, check for degenerate COND. */
if (XVECLEN (exp, 0) == 0)
return make_canonical (attr, XEXP (exp, 1));
defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
for (unit = units; unit; unit = unit->next)
{
- rtx min_issue = make_numeric_value (unit->issue_delay.min);
-
unit->condexp = check_attr_test (unit->condexp, 0);
for (op = unit->ops; op; op = op->next)
* sizeof (struct function_unit_op *));
for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next)
- bcopy (unit_ops[unit->num], &op_array[i],
+ bcopy ((char *) unit_ops[unit->num], (char *) &op_array[i],
unit->num_opclasses * sizeof (struct function_unit_op *));
/* Compute the ready cost function for each unit by computing the
candidate insn, so in the expressions below, C is a known
term and E is an unknown term.
+ We compute the blockage cost for each E for every possible C.
+ Thus OP represents E, and READYCOST is a list of values for
+ every possible C.
+
The issue delay function for C is op->issue_exp and is used to
write the `<name>_unit_conflict_cost' function. Symbolicly
this is "ISSUE-DELAY (E,C)".
for (op = unit->ops; op; op = op->next)
{
- rtx blockage = readycost;
- int delay = op->ready - 1;
+ rtx blockage = operate_exp (POS_MINUS_OP, readycost,
+ make_numeric_value (1));
if (unit->simultaneity != 0)
- delay = MIN (delay, ((unit->simultaneity - 1)
- * unit->issue_delay.min));
+ {
+ rtx filltime = make_numeric_value ((unit->simultaneity - 1)
+ * unit->issue_delay.min);
+ blockage = operate_exp (MIN_OP, blockage, filltime);
+ }
- if (delay > 0)
- blockage = operate_exp (POS_MINUS_OP, blockage,
- make_numeric_value (delay));
+ blockage = operate_exp (POS_MINUS_OP,
+ make_numeric_value (op->ready),
+ blockage);
blockage = operate_exp (MAX_OP, blockage, op->issue_exp);
blockage = simplify_knowing (blockage, unit->condexp);
then build a new expression if they don't match EXP. */
rtx defval = XEXP (exp, 1);
rtx new_defval = XEXP (exp, 1);
-
int len = XVECLEN (exp, 0);
- rtx *tests = (rtx *) alloca (len * sizeof (rtx));
+ rtunion *tests = (rtunion *) alloca (len * sizeof (rtunion));
int allsame = 1;
char *first_spacer;
/* This lets us free all storage allocated below, if appropriate. */
first_spacer = (char *) obstack_finish (rtl_obstack);
- bcopy (&XVECEXP (exp, 0, 0), tests, len * sizeof (rtx));
+ bcopy ((char *) XVEC (exp, 0)->elem, (char *) tests, len * sizeof (rtunion));
/* See if default value needs simplification. */
if (GET_CODE (defval) == COND)
rtx newtest, newval;
/* Simplify this test. */
- newtest = SIMPLIFY_TEST_EXP (tests[i], insn_code, insn_index);
- tests[i] = newtest;
+ newtest = SIMPLIFY_TEST_EXP (tests[i].rtx, insn_code, insn_index);
+ tests[i].rtx = newtest;
- newval = tests[i + 1];
+ newval = tests[i + 1].rtx;
/* See if this value may need simplification. */
if (GET_CODE (newval) == COND)
newval = simplify_cond (newval, insn_code, insn_index);
/* If test is true, make this value the default
and discard this + any following tests. */
len = i;
- defval = tests[i + 1];
+ defval = tests[i + 1].rtx;
new_defval = newval;
}
{
/* If test is false, discard it and its value. */
for (j = i; j < len - 2; j++)
- tests[j] = tests[j + 2];
+ tests[j].rtx = tests[j + 2].rtx;
len -= 2;
}
- else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
+ else if (i > 0 && attr_equal_p (newval, tests[i - 1].rtx))
{
/* If this value and the value for the prev test are the same,
merge the tests. */
- tests[i - 2]
- = insert_right_side (IOR, tests[i - 2], newtest,
+ tests[i - 2].rtx
+ = insert_right_side (IOR, tests[i - 2].rtx, newtest,
insn_code, insn_index);
/* Delete this test/value. */
for (j = i; j < len - 2; j++)
- tests[j] = tests[j + 2];
+ tests[j].rtx = tests[j + 2].rtx;
len -= 2;
}
else
- tests[i + 1] = newval;
+ tests[i + 1].rtx = newval;
}
/* If the last test in a COND has the same value
as the default value, that test isn't needed. */
- while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
+ while (len > 0 && attr_equal_p (tests[len - 1].rtx, new_defval))
len -= 2;
/* See if we changed anything. */
allsame = 0;
else
for (i = 0; i < len; i++)
- if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
+ if (! attr_equal_p (tests[i].rtx, XVECEXP (exp, 0, i)))
{
allsame = 0;
break;
rtx newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (len);
- bcopy (tests, &XVECEXP (newexp, 0, 0), len * sizeof (rtx));
+ bcopy ((char *) tests, (char *) XVEC (newexp, 0)->elem,
+ len * sizeof (rtunion));
XEXP (newexp, 1) = new_defval;
return newexp;
}
av->num_insns--;
if (ie->insn_code == -1)
av->has_asm_insn = 0;
+
+ num_insn_ents--;
}
/* Insert an insn entry in an attribute value list. */
av->num_insns++;
if (ie->insn_code == -1)
av->has_asm_insn = 1;
+
+ num_insn_ents++;
}
\f
/* This is a utility routine to take an expression that is a tree of either
For each possible COND value, call ourselves recursively.
The extra TRUE and FALSE expressions will be eliminated by another
- call to the simplification routine. */
+ call to the simplification routine. */
orexp = false_rtx;
andexp = true_rtx;
rtx newexp = exp;
char *spacer = (char *) obstack_finish (rtl_obstack);
- static rtx loser = 0;
- static int count = 0;
- static stopcount = 0;
-
- if (exp == loser)
- do_nothing ();
- count++;
- if (count == stopcount)
- do_nothing ();
-
/* Don't re-simplify something we already simplified. */
if (RTX_UNCHANGING_P (exp) || MEM_IN_STRUCT_P (exp))
return exp;
{
i = compute_alternative_mask (exp, AND);
if (i & ~insn_alternatives[insn_code])
- fatal ("Illegal alternative specified for pattern number %d",
+ fatal ("Invalid alternative specified for pattern number %d",
insn_index);
- /* If all alternatives are excluded, this is false. */
+ /* If all alternatives are excluded, this is false. */
i ^= insn_alternatives[insn_code];
if (i == 0)
return false_rtx;
{
i = compute_alternative_mask (exp, IOR);
if (i & ~insn_alternatives[insn_code])
- fatal ("Illegal alternative specified for pattern number %d",
+ fatal ("Invalid alternative specified for pattern number %d",
insn_index);
- /* If all alternatives are included, this is true. */
+ /* If all alternatives are included, this is true. */
i ^= insn_alternatives[insn_code];
if (i == 0)
return true_rtx;
return newexp;
}
-
-do_nothing ()
-{}
\f
/* Optimize the attribute lists by seeing if we can determine conditional
values from the known values of other attributes. This will save subroutine
struct attr_desc * attr;
struct attr_value_list *next; };
struct attr_value_list **insn_code_values;
+ struct attr_value_list *ivbuf;
struct attr_value_list *iv;
/* For each insn code, make a list of all the insn_ent's for it,
for all values for all attributes. */
+ if (num_insn_ents == 0)
+ return;
+
/* Make 2 extra elements, for "code" values -2 and -1. */
insn_code_values
= (struct attr_value_list **) alloca ((insn_code_number + 2)
* sizeof (struct attr_value_list *));
- bzero (insn_code_values,
+ bzero ((char *) insn_code_values,
(insn_code_number + 2) * sizeof (struct attr_value_list *));
+
/* Offset the table address so we can index by -2 or -1. */
insn_code_values += 2;
+ /* Allocate the attr_value_list structures using xmalloc rather than
+ alloca, because using alloca can overflow the maximum permitted
+ stack limit on SPARC Lynx. */
+ iv = ivbuf = ((struct attr_value_list *)
+ xmalloc (num_insn_ents * sizeof (struct attr_value_list)));
+
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
for (av = attr->first_value; av; av = av->next)
for (ie = av->first_insn; ie; ie = ie->next)
{
- iv = ((struct attr_value_list *)
- alloca (sizeof (struct attr_value_list)));
iv->attr = attr;
iv->av = av;
iv->ie = ie;
iv->next = insn_code_values[ie->insn_code];
insn_code_values[ie->insn_code] = iv;
+ iv++;
}
+ /* Sanity check on num_insn_ents. */
+ if (iv != ivbuf + num_insn_ents)
+ abort ();
+
/* Process one insn code at a time. */
for (i = -2; i < insn_code_number; i++)
{
}
}
}
+
+ free (ivbuf);
}
#if 0
\f
/* Clear the MEM_IN_STRUCT_P flag in EXP and its subexpressions. */
+static void
clear_struct_flag (x)
rtx x;
{
case PC:
case CC0:
case EQ_ATTR:
+ case ATTR_FLAG:
return;
}
/* Return the number of RTX objects making up the expression X.
But if we count more more than MAX objects, stop counting. */
+static int
count_sub_rtxs (x, max)
rtx x;
int max;
case PC:
case CC0:
case EQ_ATTR:
+ case ATTR_FLAG:
return 1;
}
if (! strcmp (attr->name, "length") && ! attr->is_numeric)
fatal ("`length' attribute must take numeric values");
- /* Set up the default value. */
+ /* Set up the default value. */
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
}
case PLUS: case MINUS: case MULT: case DIV: case MOD:
case AND: case IOR: case XOR:
- case LSHIFT: case ASHIFT: case LSHIFTRT: case ASHIFTRT:
+ case ASHIFT: case LSHIFTRT: case ASHIFTRT:
write_test_expr (XEXP (exp, 0), in_comparison || comparison_operator);
switch (code)
{
case XOR:
printf (" ^ ");
break;
- case LSHIFT:
case ASHIFT:
printf (" << ");
break;
if (attr->is_const)
{
write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
- 0, 0),
+ -2, -2),
in_comparison);
}
else
}
break;
+ /* Comparison test of flags for define_delays. */
+ case ATTR_FLAG:
+ if (in_comparison)
+ fatal ("ATTR_FLAG not valid inside comparison");
+ printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
+ break;
+
/* See if an operand matches a predicate. */
case MATCH_OPERAND:
/* If only a mode is given, just ensure the mode matches the operand.
XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
break;
- /* Constant integer. */
+ /* Constant integer. */
case CONST_INT:
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
printf ("%d", XWINT (exp, 0));
#endif
break;
- /* A random C expression. */
+ /* A random C expression. */
case SYMBOL_REF:
printf ("%s", XSTR (exp, 0));
break;
/* The address of the branch target. */
case MATCH_DUP:
- printf ("insn_addresses[INSN_UID (JUMP_LABEL (insn))]");
+ printf ("insn_addresses[INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])]",
+ XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
/* The address of the current insn. It would be more consistent with
return;
case MATCH_DUP:
+ must_extract = 1;
+ address_used = 1;
+ return;
+
case PC:
address_used = 1;
return;
+
+ case ATTR_FLAG:
+ return;
}
for (i = 0, fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
struct attr_value *av, *common_av;
/* Find the most used attribute value. Handle that as the `default' of the
- switch we will generate. */
+ switch we will generate. */
common_av = find_most_used (attr);
/* Write out start of function, then all values with explicit `case' lines,
/* Write function prelude. */
printf ("int\n");
- printf ("eligible_for_%s (delay_insn, slot, candidate_insn)\n", kind);
+ printf ("eligible_for_%s (delay_insn, slot, candidate_insn, flags)\n",
+ kind);
printf (" rtx delay_insn;\n");
printf (" int slot;\n");
printf (" rtx candidate_insn;\n");
+ printf (" int flags;\n");
printf ("{\n");
printf (" rtx insn;\n");
printf ("\n");
printf ("{\n");
printf (" rtx insn;\n");
printf (" int casenum;\n\n");
- printf (" insn = candidate_insn;\n");
+ printf (" insn = executing_insn;\n");
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
/* Now write an outer switch statement on each case. Then write
the tests on the executing function within each. */
- printf (" insn = executing_insn;\n");
+ printf (" insn = candidate_insn;\n");
printf (" switch (casenum)\n");
printf (" {\n");
PUT_MODE (copy, GET_MODE (orig));
RTX_UNCHANGING_P (copy) = 1;
- bcopy (&XEXP (orig, 0), &XEXP (copy, 0),
+ bcopy ((char *) &XEXP (orig, 0), (char *) &XEXP (copy, 0),
GET_RTX_LENGTH (GET_CODE (copy)) * sizeof (rtx));
return copy;
#endif
static void
fatal (s, a1, a2)
char *s;
+ char *a1, *a2;
{
fprintf (stderr, "genattrtab: ");
fprintf (stderr, s, a1, a2);
{
struct rlimit rlim;
- /* Set the stack limit huge so that alloca does not fail. */
+ /* Set the stack limit huge so that alloca does not fail. */
getrlimit (RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit (RLIMIT_STACK, &rlim);
/* Construct extra attributes for `length'. */
make_length_attrs ();
- /* Perform any possible optimizations to speed up compilation. */
+ /* Perform any possible optimizations to speed up compilation. */
optimize_attrs ();
/* Now write out all the `gen_attr_...' routines. Do these before the