/* This program handles insn attribues and the DEFINE_DELAY and
DEFINE_FUNCTION_UNIT definitions.
- It produces a series of functions call `get_attr_...', one for each
+ It produces a series of functions named `get_attr_...', one for each insn
attribute. Each of these is given the rtx for an insn and returns a member
of the enum for the attribute.
changed are made. The resulting lengths are saved for use by
`get_attr_length'.
+ A special form of DEFINE_ATTR, where the expression for default value is a
+ CONST expression, indicates an attribute that is constant for a given run
+ of the compiler. The subroutine generated for these attributes has no
+ parameters as it does not depend on any particular insn. Constant
+ attributes are typically used to specify which variety of processor is
+ used.
+
Internal attributes are defined to handle DEFINE_DELAY and
DEFINE_FUNCTION_UNIT. Special routines are output for these cases.
optimization simplify them.
Once optimization is complete, any required routines and definitions
- will be written. */
+ will be written.
+
+ An optimization that is not yet implemented is to hoist the constant
+ expressions entirely out of the routines and definitions that are written.
+ A way to do this is to iterate over all possible combinations of values
+ for constant attributes and generate a set of functions for that given
+ combination. An initialization function would be written that evaluates
+ the attributes and installs the corresponding set of routines and
+ definitions (each would be accessed through a pointer). */
#include <stdio.h>
+#include "gvarargs.h"
#include "config.h"
#include "rtl.h"
#include "obstack.h"
char *name; /* Name of attribute. */
struct attr_desc *next; /* Next attribute. */
int is_numeric; /* Values of this attribute are numeric. */
+ 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. */
rtx frame_pointer_rtx, stack_pointer_rtx, arg_pointer_rtx;
+static rtx attr_rtx ();
+static char *attr_printf ();
+static char *attr_string ();
static rtx check_attr_test ();
static void check_attr_value ();
static rtx convert_set_attr_alternative ();
static rtx convert_set_attr ();
static void check_defs ();
+static rtx convert_const_symbol_ref ();
static rtx make_canonical ();
static struct attr_value *get_attr_value ();
static void expand_delays ();
char *xmalloc ();
static void fatal ();
\f
+/* Hash table for sharing RTL and strings. */
+
+/* Each hash table slot is a bucket containing a chain of these structures.
+ Strings are given negative hash codes; RTL expressions are given positive
+ hash codes. */
+
+struct attr_hash
+{
+ struct attr_hash *next; /* Next structure in the bucket. */
+ int hashcode; /* Hash code of this rtx or string. */
+ union
+ {
+ char *str; /* The string (negative hash codes) */
+ rtx rtl; /* or the RTL recorded here. */
+ } u;
+};
+
+/* Now here is the hash table. When recording an RTL, it is added to
+ the slot whose index is the hash code mod the table size. Note
+ that the hash table is used for several kinds of RTL (see attr_rtx)
+ and for strings. While all these live in the same table, they are
+ completely independent, and the hash code is computed differently
+ for each. */
+
+#define RTL_HASH_SIZE 4093
+struct attr_hash *attr_hash_table[RTL_HASH_SIZE];
+
+/* Here is how primitive or already-shared RTL's hash
+ codes are made. */
+#define RTL_HASH(RTL) ((int) (RTL) & 0777777)
+
+/* Add an entry to the hash table for RTL with hash code HASHCODE. */
+
+static void
+attr_hash_add_rtx (hashcode, rtl)
+ int hashcode;
+ rtx rtl;
+{
+ register struct attr_hash *h;
+
+ h = (struct attr_hash *) xmalloc (sizeof (struct attr_hash));
+ h->hashcode = hashcode;
+ h->u.rtl = rtl;
+ h->next = attr_hash_table[hashcode % RTL_HASH_SIZE];
+ attr_hash_table[hashcode % RTL_HASH_SIZE] = h;
+}
+
+/* Add an entry to the hash table for STRING with hash code HASHCODE. */
+
+static void
+attr_hash_add_string (hashcode, str)
+ int hashcode;
+ char *str;
+{
+ register struct attr_hash *h;
+
+ h = (struct attr_hash *) xmalloc (sizeof (struct attr_hash));
+ h->hashcode = -hashcode;
+ h->u.str = str;
+ h->next = attr_hash_table[hashcode % RTL_HASH_SIZE];
+ attr_hash_table[hashcode % RTL_HASH_SIZE] = h;
+}
+
+/* Generate an RTL expression, but allow sharing. Like gen_rtx, but the
+ mode is not used:
+
+ rtx attr_rtx (code, [element1, ..., elementn]) */
+
+/*VARARGS1*/
+static rtx
+attr_rtx (va_alist)
+ va_dcl
+{
+ va_list p;
+ enum rtx_code code;
+ register int i; /* Array indices... */
+ register char *fmt; /* Current rtx's format... */
+ register rtx rt_val; /* RTX to return to caller... */
+ int hashcode;
+ register struct attr_hash *h;
+
+ va_start (p);
+ code = va_arg (p, enum rtx_code);
+
+ /* 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
+ to the table. */
+
+ if (GET_RTX_CLASS (code) == '1')
+ {
+ rtx arg0 = va_arg (p, rtx);
+
+ hashcode = (code + RTL_HASH (arg0));
+ for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
+ if (h->hashcode == hashcode
+ && GET_CODE (h->u.rtl) == code
+ && XEXP (h->u.rtl, 0) == arg0)
+ goto found;
+
+ if (h == 0)
+ {
+ rt_val = rtx_alloc (code);
+ XEXP (rt_val, 0) = arg0;
+ }
+ }
+ else if (GET_RTX_CLASS (code) == 'c'
+ || GET_RTX_CLASS (code) == '2'
+ || GET_RTX_CLASS (code) == '<')
+ {
+ rtx arg0 = va_arg (p, rtx);
+ rtx arg1 = va_arg (p, rtx);
+
+ hashcode = (code + RTL_HASH (arg0) + RTL_HASH (arg1));
+ for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
+ if (h->hashcode == hashcode
+ && GET_CODE (h->u.rtl) == code
+ && XEXP (h->u.rtl, 0) == arg0
+ && XEXP (h->u.rtl, 1) == arg1)
+ goto found;
+
+ if (h == 0)
+ {
+ rt_val = rtx_alloc (code);
+ XEXP (rt_val, 0) = arg0;
+ XEXP (rt_val, 1) = arg1;
+ }
+ }
+ else if (GET_RTX_LENGTH (code) == 1
+ && GET_RTX_FORMAT (code)[0] == 's')
+ {
+ char * arg0 = va_arg (p, char *);
+
+ hashcode = (code + RTL_HASH (arg0));
+ for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
+ if (h->hashcode == hashcode
+ && GET_CODE (h->u.rtl) == code
+ && XSTR (h->u.rtl, 0) == arg0)
+ goto found;
+
+ if (h == 0)
+ {
+ rt_val = rtx_alloc (code);
+ XSTR (rt_val, 0) = arg0;
+ }
+ }
+ else if (GET_RTX_LENGTH (code) == 2
+ && GET_RTX_FORMAT (code)[0] == 's'
+ && GET_RTX_FORMAT (code)[1] == 's')
+ {
+ char * arg0 = va_arg (p, char *);
+ char * arg1 = va_arg (p, char *);
+
+ hashcode = (code + RTL_HASH (arg0) + RTL_HASH (arg1));
+ for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
+ if (h->hashcode == hashcode
+ && GET_CODE (h->u.rtl) == code
+ && XSTR (h->u.rtl, 0) == arg0
+ && XSTR (h->u.rtl, 1) == arg1)
+ goto found;
+
+ if (h == 0)
+ {
+ rt_val = rtx_alloc (code);
+ XSTR (rt_val, 0) = arg0;
+ XSTR (rt_val, 1) = arg1;
+ }
+ }
+ else
+ {
+ rt_val = rtx_alloc (code); /* Allocate the storage space. */
+
+ fmt = GET_RTX_FORMAT (code); /* Find the right format... */
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ {
+ switch (*fmt++)
+ {
+ case '0': /* Unused field. */
+ break;
+
+ case 'i': /* An integer? */
+ XINT (rt_val, i) = va_arg (p, int);
+ break;
+
+ case 's': /* A string? */
+ XSTR (rt_val, i) = va_arg (p, char *);
+ break;
+
+ case 'e': /* An expression? */
+ case 'u': /* An insn? Same except when printing. */
+ XEXP (rt_val, i) = va_arg (p, rtx);
+ break;
+
+ case 'E': /* An RTX vector? */
+ XVEC (rt_val, i) = va_arg (p, rtvec);
+ break;
+
+ default:
+ abort();
+ }
+ }
+ va_end (p);
+ return rt_val;
+ }
+
+ va_end (p);
+ attr_hash_add_rtx (hashcode, rt_val);
+ return rt_val;
+
+ found:
+ va_end (p);
+ return h->u.rtl;
+}
+
+/* Create a new string printed with the printf line arguments into a space
+ of at most LEN bytes:
+
+ rtx attr_printf (len, format, [arg1, ..., argn]) */
+
+/*VARARGS2*/
+static char *
+attr_printf (va_alist)
+ va_dcl
+{
+ va_list p;
+ register int len;
+ register char *fmt;
+ register char *str;
+
+ /* Print the string into a temporary location. */
+ va_start (p);
+ len = va_arg (p, int);
+ str = (char *) alloca (len);
+ fmt = va_arg (p, char *);
+ vsprintf (str, fmt, p);
+ va_end (p);
+
+ return attr_string (str, strlen (str));
+}
+
+/* Return a permanent (possibly shared) copy of a string STR (not assumed
+ to be null terminated) with LEN bytes. */
+
+static char *
+attr_string (str, len)
+ char *str;
+ int len;
+{
+ register struct attr_hash *h;
+ int hashcode;
+ int i;
+ register char *new_str;
+
+ /* Compute the hash code. */
+ hashcode = (len + 1) * 613 + (unsigned)str[0];
+ for (i = 1; i <= len; i += 2)
+ hashcode = ((hashcode * 613) + (unsigned)str[i]);
+ if (hashcode < 0)
+ hashcode = -hashcode;
+
+ /* Search the table for the string. */
+ for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
+ if (h->hashcode == -hashcode
+ && !strcmp (h->u.str, str))
+ return h->u.str; /* <-- return if found. */
+
+ /* Not found; create a permanent copy and add it to the hash table. */
+ new_str = (char *) xmalloc (len + 1);
+ bcopy (str, new_str, len);
+ new_str[len] = '\0';
+ attr_hash_add_string (hashcode, new_str);
+
+ return new_str; /* Return the new string. */
+}
+\f
/* Given a test expression for an attribute, ensure it is validly formed.
+ IS_CONST indicates whether the expression is constant for each compiler
+ run (a constant expression may not test any particular insn).
+
Convert (eq_attr "att" "a1,a2") to (ior (eq_attr ... ) (eq_attrq ..))
and (eq_attr "att" "!a1") to (not (eq_attr "att" "a1")). Do the latter
test first so that (eq_attr "att" "!a1,a2,a3") works as expected.
Return the new expression, if any. */
static rtx
-check_attr_test (exp)
+check_attr_test (exp, is_const)
rtx exp;
+ int is_const;
{
struct attr_desc *attr;
struct attr_value *av;
case EQ_ATTR:
/* Handle negation test. */
if (XSTR (exp, 1)[0] == '!')
- {
- XSTR(exp, 1) = &XSTR(exp, 1)[1];
- newexp = rtx_alloc (NOT);
- XEXP (newexp, 0) = exp;
-
- return check_attr_test (newexp);
- }
+ return check_attr_test (attr_rtx (NOT,
+ attr_rtx (EQ_ATTR,
+ XSTR (exp, 0),
+ &XSTR(exp, 1)[1])),
+ is_const);
else if (n_comma_elts (XSTR (exp, 1)) == 1)
{
fatal ("Unknown attribute `%s' in EQ_ATTR", XEXP (exp, 0));
}
+ if (is_const && ! attr->is_const)
+ fatal ("Constant expression uses insn attribute `%s' in EQ_ATTR",
+ XEXP (exp, 0));
+
XSTR (exp, 0) = attr->name;
if (attr->is_numeric)
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
- newexp = rtx_alloc (EQ_ATTR);
- XSTR (newexp, 0) = XSTR (exp, 0);
- XSTR (newexp, 1) = p;
+ newexp = attr_rtx (EQ_ATTR, XSTR (exp, 0), p);
orexp = insert_right_side (IOR, orexp, newexp, -2);
}
- return check_attr_test (orexp);
+ return check_attr_test (orexp, is_const);
}
break;
case IOR:
case AND:
- XEXP (exp, 0) = check_attr_test (XEXP (exp, 0));
- XEXP (exp, 1) = check_attr_test (XEXP (exp, 1));
+ XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const);
+ XEXP (exp, 1) = check_attr_test (XEXP (exp, 1), is_const);
break;
case NOT:
- XEXP (exp, 0) = check_attr_test (XEXP (exp, 0));
+ XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const);
break;
case MATCH_OPERAND:
+ if (is_const)
+ fatal ("RTL operator \"%s\" not valid in constant attribute test",
+ GET_RTX_NAME (MATCH_OPERAND));
+
case LE: case LT: case GT: case GE:
case LEU: case LTU: case GTU: case GEU:
case NE: case EQ:
RTX_UNCHANGING_P (exp) = 1;
break;
+ case SYMBOL_REF:
+ if (is_const)
+ {
+ /* These cases are valid for constant attributes, but can't be
+ simplified. */
+ RTX_UNCHANGING_P (exp) = 1;
+ break;
+ }
default:
fatal ("RTL operator \"%s\" not valid in attribute test",
GET_RTX_NAME (GET_CODE (exp)));
return;
case IF_THEN_ELSE:
- XEXP (exp, 0) = check_attr_test (XEXP (exp, 0));
+ XEXP (exp, 0) = check_attr_test (XEXP (exp, 0),
+ attr ? attr->is_const : 0);
check_attr_value (XEXP (exp, 1), attr);
check_attr_value (XEXP (exp, 2), attr);
return;
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
- XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i));
+ XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i),
+ attr ? attr->is_const : 0);
check_attr_value (XVECEXP (exp, 0, i + 1), attr);
}
check_attr_value (XEXP (exp, 1), attr);
return;
+ case SYMBOL_REF:
+ if (attr && attr->is_const)
+ /* A constant SYMBOL_REF is valid as a constant attribute test and
+ is expanded later by make_canonical into a COND. */
+ return;
+ /* Otherwise, fall through... */
+
default:
fatal ("Illegal operation `%s' for attribute value",
GET_RTX_NAME (GET_CODE (exp)));
for (i = 0; i < num_alt - 1; i++)
{
+ char *p;
+ p = attr_printf (3, "%d", i);
+
+ /* Sharing this EQ_ATTR rtl causes trouble. */
XVECEXP (condexp, 0, 2 * i) = rtx_alloc (EQ_ATTR);
XSTR (XVECEXP (condexp, 0, 2 * i), 0) = alternative_name;
- XSTR (XVECEXP (condexp, 0, 2 * i), 1) = (char *) xmalloc (3);
- sprintf (XSTR (XVECEXP (condexp, 0, 2 * i), 1), "%d", i);
+ XSTR (XVECEXP (condexp, 0, 2 * i), 1) = p;
XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP (exp, 1, i);
}
XEXP (condexp, 1) = XVECEXP (exp, 1, i);
- newexp = rtx_alloc (SET);
- XEXP (newexp, 0) = rtx_alloc (ATTR);
- XSTR (XEXP (newexp, 0), 0) = XSTR (exp, 0);
- XEXP (newexp, 1) = condexp;
-
- return newexp;
+ return attr_rtx (SET, attr_rtx (ATTR, XSTR (exp, 0)), condexp);
}
\f
/* Given a SET_ATTR, convert to the appropriate SET. If a comma-separated
/* See how many alternative specified. */
n = n_comma_elts (XSTR (exp, 1));
if (n == 1)
- {
- newexp = rtx_alloc (SET);
- XEXP (newexp, 0) = rtx_alloc (ATTR);
- XSTR (XEXP (newexp, 0), 0) = XSTR (exp, 0);
- XEXP (newexp, 1) = rtx_alloc (CONST_STRING);
- XSTR (XEXP (newexp, 1), 0) = XSTR (exp, 1);
-
- return newexp;
- }
+ return attr_rtx (SET,
+ attr_rtx (ATTR, XSTR (exp, 0)),
+ attr_rtx (CONST_STRING, XSTR (exp, 1)));
newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);
XSTR (newexp, 0) = XSTR (exp, 0);
name_ptr = XSTR (exp, 1);
n = 0;
while ((p = next_comma_elt (&name_ptr)) != NULL)
- {
- XVECEXP (newexp, 1, n) = rtx_alloc (CONST_STRING);
- XSTR (XVECEXP (newexp, 1, n++), 0) = p;
- }
+ XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
return convert_set_attr_alternative (newexp, num_alt, insn_code, insn_index);
}
}
}
\f
+/* Given a constant SYMBOL_REF expression, convert to a COND that
+ explicitly tests each enumerated value. */
+
+static rtx
+convert_const_symbol_ref (exp, attr)
+ rtx exp;
+ struct attr_desc *attr;
+{
+ rtx condexp;
+ struct attr_value *av;
+ int i;
+ int num_alt = 0;
+
+ for (av = attr->first_value; av; av = av->next)
+ num_alt++;
+
+ /* Make a COND with all tests but the last, and in the original order.
+ Select the last value via the default. Note that the attr values
+ are constructed in reverse order. */
+
+ condexp = rtx_alloc (COND);
+ XVEC (condexp, 0) = rtvec_alloc ((num_alt - 1) * 2);
+ av = attr->first_value;
+ XEXP (condexp, 1) = av->value;
+
+ for (i = num_alt - 2; av = av->next, i >= 0; i--)
+ {
+ char * p;
+ rtx value;
+
+ XVECEXP (condexp, 0, 2 * i) = rtx_alloc (EQ);
+ XEXP (XVECEXP (condexp, 0, 2 * i), 0) = exp;
+ XEXP (XVECEXP (condexp, 0, 2 * i), 1) = value = rtx_alloc (SYMBOL_REF);
+ RTX_UNCHANGING_P (value) = 1;
+ XSTR (value, 0) = p = (char *) xmalloc (2
+ + strlen (attr->name)
+ + strlen (XSTR (av->value, 0)));
+ strcpy (p, attr->name);
+ strcat (p, "_");
+ strcat (p, XSTR (av->value, 0));
+ for (; *p != '\0'; p++)
+ if (*p >= 'a' && *p <= 'z')
+ *p -= 'a' - 'A';
+
+ XVECEXP (condexp, 0, 2 * i + 1) = av->value;
+ }
+
+ return condexp;
+}
+\f
/* Given a valid expression for an attribute value, remove any IF_THEN_ELSE
expressions by converting them into a COND. This removes cases from this
program. Also, replace an attribute value of "*" with the default attribute
break;
+ case SYMBOL_REF:
+ if (!attr->is_const || RTX_UNCHANGING_P (exp))
+ break;
+ RTX_UNCHANGING_P (exp) = 1;
+ exp = convert_const_symbol_ref (exp, attr);
+ check_attr_value (exp, attr);
+ /* Goto COND case since this is now a COND. Note that while the
+ new expression is rescanned, all symbol_ref notes are mared as
+ unchanging. */
+ goto cond;
+
case IF_THEN_ELSE:
newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (2);
/* Fall through to COND case since this is now a COND. */
case COND:
+ cond:
/* First, check for degenerate COND. */
if (XVECLEN (exp, 0) == 0)
return make_canonical (attr, XEXP (exp, 1));
{
for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
{
- newexp = rtx_alloc (IF_THEN_ELSE);
condexp = XVECEXP (delay->def, 1, i);
if (condexp == 0) condexp = false_rtx;
- XEXP (newexp, 0) = condexp;
- XEXP (newexp, 1) = make_numeric_value (1);
- XEXP (newexp, 2) = make_numeric_value (0);
+ newexp = attr_rtx (IF_THEN_ELSE, condexp,
+ make_numeric_value (1), make_numeric_value (0));
- p = (char *) xmalloc (13);
- sprintf (p, "*delay_%d_%d", delay->num, i / 3);
+ p = attr_printf (13, "*delay_%d_%d", delay->num, i / 3);
make_internal_attr (p, newexp, 1);
if (have_annul_true)
{
- newexp = rtx_alloc (IF_THEN_ELSE);
condexp = XVECEXP (delay->def, 1, i + 1);
if (condexp == 0) condexp = false_rtx;
- XEXP (newexp, 0) = condexp;
- XEXP (newexp, 1) = make_numeric_value (1);
- XEXP (newexp, 2) = make_numeric_value (0);
- p = (char *) xmalloc (18);
- sprintf (p, "*annul_true_%d_%d", delay->num, i / 3);
+ newexp = attr_rtx (IF_THEN_ELSE, condexp,
+ make_numeric_value (1),
+ make_numeric_value (0));
+ p = attr_printf (18, "*annul_true_%d_%d", delay->num, i / 3);
make_internal_attr (p, newexp, 1);
}
if (have_annul_false)
{
- newexp = rtx_alloc (IF_THEN_ELSE);
condexp = XVECEXP (delay->def, 1, i + 2);
if (condexp == 0) condexp = false_rtx;
- XEXP (newexp, 0) = condexp;
- XEXP (newexp, 1) = make_numeric_value (1);
- XEXP (newexp, 2) = make_numeric_value (0);
- p = (char *) xmalloc (18);
- sprintf (p, "*annul_false_%d_%d", delay->num, i / 3);
+ newexp = attr_rtx (IF_THEN_ELSE, condexp,
+ make_numeric_value (1),
+ make_numeric_value (0));
+ p = attr_printf (18, "*annul_false_%d_%d", delay->num, i / 3);
make_internal_attr (p, newexp, 1);
}
}
else if (GET_CODE (right) == IF_THEN_ELSE)
{
/* Apply recursively to all values within. */
- newexp = rtx_alloc (IF_THEN_ELSE);
- XEXP (newexp, 0) = XEXP (right, 0);
- XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1));
- XEXP (newexp, 2) = operate_exp (op, left, XEXP (right, 2));
-
- return newexp;
+ return attr_rtx (IF_THEN_ELSE, XEXP (right, 0),
+ operate_exp (op, left, XEXP (right, 1)),
+ operate_exp (op, left, XEXP (right, 2)));
}
else if (GET_CODE (right) == COND)
{
/* Otherwise, do recursion the other way. */
else if (GET_CODE (left) == IF_THEN_ELSE)
{
- newexp = rtx_alloc (IF_THEN_ELSE);
- XEXP (newexp, 0) = XEXP (left, 0);
- XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right);
- XEXP (newexp, 2) = operate_exp (op, XEXP (left, 2), right);
-
- return newexp;
+ return attr_rtx (IF_THEN_ELSE, XEXP (left, 0),
+ operate_exp (op, XEXP (left, 1), right),
+ operate_exp (op, XEXP (left, 2), right));
}
else if (GET_CODE (left) == COND)
for (op = unit->ops; op; op = op->next)
{
- str = (char *) xmalloc (strlen (unit->name) + 11);
-
/* Validate the expressions we were given for the conditions
and busy cost. Then make an attribute for use in the conflict
function. */
- op->condexp = check_attr_test (op->condexp);
+ op->condexp = check_attr_test (op->condexp, 0);
check_attr_value (op->busyexp, 0);
- sprintf (str, "*%s_case_%d", unit->name, op->num);
+ str = attr_printf (strlen (unit->name) + 11, "*%s_case_%d",
+ unit->name, op->num);
make_internal_attr (str, make_canonical (0, op->busyexp));
/* Make our adjustment to the two COND's being computed. If we are
}
/* Make an attribute for the case number and ready delay. */
- str = (char *) xmalloc (strlen (unit->name) + 8);
- sprintf (str, "*%s_cases", unit->name);
+ str = attr_printf (strlen (unit->name) + 8, "*%s_cases", unit->name);
make_internal_attr (str, caseexp, 1);
- str = (char *) xmalloc (strlen (unit->name) + 20);
- sprintf (str, "*%s_unit_ready_cost", unit->name);
+ str = attr_printf (strlen (unit->name) + 20, "*%s_unit_ready_cost",
+ unit->name);
make_internal_attr (str, readyexp, 0);
/* Merge this function unit into the ready cost and unit mask
attributes. */
- XEXP (newexp, 0) = check_attr_test (unit->condexp);
+ XEXP (newexp, 0) = check_attr_test (unit->condexp, 0);
XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
unitsmask = operate_exp (OR_OP, unitsmask, newexp);
if (address_used)
return (*address_fn) (exp);
- newexp = rtx_alloc (IF_THEN_ELSE);
- XEXP (newexp, 0) = substitute_address (XEXP (exp, 0),
- no_address_fn, address_fn);
- XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
- no_address_fn, address_fn);
- XEXP (newexp, 2) = substitute_address (XEXP (exp, 2),
- no_address_fn, address_fn);
-
- return newexp;
+ return attr_rtx (IF_THEN_ELSE,
+ substitute_address (XEXP (exp, 0),
+ no_address_fn, address_fn),
+ substitute_address (XEXP (exp, 1),
+ no_address_fn, address_fn),
+ substitute_address (XEXP (exp, 2),
+ no_address_fn, address_fn));
}
return (*no_address_fn) (exp);
if (! length_attr->is_numeric)
fatal ("length attribute must be numeric.");
+ length_attr->is_const = 0;
length_attr->is_special = 1;
/* Make each new attribute, in turn. */
if (GET_CODE (exp) == code)
{
/* Make a copy of this expression and call recursively. */
- newexp = rtx_alloc (code);
- XEXP (newexp, 0) = XEXP (exp, 0);
- XEXP (newexp, 1) = insert_right_side (code, XEXP (exp, 1),
- term, insn_code, insn_index);
+ newexp = attr_rtx (code, XEXP (exp, 0),
+ insert_right_side (code, XEXP (exp, 1),
+ term, insn_code, insn_index));
}
else
{
/* Insert the new term. */
- newexp = rtx_alloc (code);
- XEXP (newexp, 0) = exp;
- XEXP (newexp, 1) = term;
+ newexp = attr_rtx (code, exp, term);
}
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
for (i = 0; (mask & (1 << i)) == 0; i++)
;
- alternative = (char *) xmalloc (3);
- sprintf (alternative, "%d", i);
+ alternative = attr_printf (3, "%d", i);
- newexp = rtx_alloc (EQ_ATTR);
- XSTR (newexp, 0) = alternative_name;
- XSTR (newexp, 1) = alternative;
+ newexp = attr_rtx (EQ_ATTR, alternative_name, alternative);
RTX_UNCHANGING_P (newexp) = 1;
return newexp;
insn_code, insn_index);
/* Add this condition into the AND expression. */
- newexp = rtx_alloc (NOT);
- XEXP (newexp, 0) = XVECEXP (value, 0, i);
+ newexp = attr_rtx (NOT, XVECEXP (value, 0, i));
andexp = insert_right_side (AND, andexp, newexp,
insn_code, insn_index);
}
right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
- newexp = rtx_alloc (GET_CODE (exp));
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (GET_CODE (exp), left, right);
exp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
- newexp = rtx_alloc (GET_CODE (exp));
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (GET_CODE (exp), left, right);
exp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
- newexp = rtx_alloc (GET_CODE (exp));
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (GET_CODE (exp), left, right);
exp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
- newexp = rtx_alloc (GET_CODE (exp));
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (GET_CODE (exp), left, right);
exp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
right = tem;
}
- newexp = rtx_alloc (IOR);
- XEXP (newexp, 0) = rtx_alloc (AND);
- XEXP (newexp, 1) = rtx_alloc (AND);
- XEXP (XEXP (newexp, 0), 0) = XEXP (XEXP (newexp, 1), 0) = left;
- XEXP (XEXP (newexp, 0), 1) = XEXP (right, 0);
- XEXP (XEXP (newexp, 1), 1) = XEXP (right, 1);
+ newexp = attr_rtx (IOR,
+ attr_rtx (AND, left, XEXP (right, 0)),
+ attr_rtx (AND, left, XEXP (right, 1)));
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
alternative and we have tested none of them! */
left = make_alternative_compare (i);
right = simplify_and_tree (exp, &left, insn_code, insn_index);
- newexp = rtx_alloc (AND);
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (AND, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
- newexp = rtx_alloc (AND);
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (AND, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
break;
else if (GET_CODE (left) == AND && GET_CODE (right) == AND
&& rtx_equal_p (XEXP (left, 0), XEXP (right, 0)))
{
- newexp = rtx_alloc (IOR);
- XEXP (newexp, 0) = XEXP (left, 1);
- XEXP (newexp, 1) = XEXP (right, 1);
+ newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1));
left = XEXP (left, 0);
right = newexp;
- newexp = rtx_alloc (AND);
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (AND, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
alternative and we have tested none of them! */
left = make_alternative_compare (i);
right = simplify_and_tree (exp, &left, insn_code, insn_index);
- newexp = rtx_alloc (IOR);
- XEXP (newexp, 0) = rtx_alloc (NOT);
- XEXP (XEXP (newexp, 0), 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (IOR, attr_rtx (NOT, left), right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
- newexp = rtx_alloc (IOR);
- XEXP (newexp, 0) = left;
- XEXP (newexp, 1) = right;
+ newexp = attr_rtx (IOR, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
break;
/* Try to apply De`Morgan's laws. */
else if (GET_CODE (left) == IOR)
{
- newexp = rtx_alloc (AND);
- XEXP (newexp, 0) = rtx_alloc (NOT);
- XEXP (XEXP (newexp, 0), 0) = XEXP (left, 0);
- XEXP (newexp, 1) = rtx_alloc (NOT);
- XEXP (XEXP (newexp, 1), 0) = XEXP (left, 1);
+ newexp = attr_rtx (AND,
+ attr_rtx (NOT, XEXP (left, 0)),
+ attr_rtx (NOT, XEXP (left, 1)));
newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
else if (GET_CODE (left) == AND)
{
- newexp = rtx_alloc (IOR);
- XEXP (newexp, 0) = rtx_alloc (NOT);
- XEXP (XEXP (newexp, 0), 0) = XEXP (left, 0);
- XEXP (newexp, 1) = rtx_alloc (NOT);
- XEXP (XEXP (newexp, 1), 0) = XEXP (left, 1);
+ newexp = attr_rtx (IOR,
+ attr_rtx (NOT, XEXP (left, 0)),
+ attr_rtx (NOT, XEXP (left, 1)));
newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
else if (left != XEXP (exp, 0))
{
- newexp = rtx_alloc (NOT);
- XEXP (newexp, 0) = left;
+ newexp = attr_rtx (NOT, left);
}
break;
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
av = (struct attr_value *) xmalloc (sizeof (struct attr_value));
- av->value = rtx_alloc (CONST_STRING);
- XSTR (av->value, 0) = p;
+ av->value = attr_rtx (CONST_STRING, p);
av->next = attr->first_value;
attr->first_value = av;
av->first_insn = NULL;
}
}
+ if (GET_CODE (XEXP (exp, 2)) == CONST)
+ {
+ attr->is_const = 1;
+ if (attr->is_numeric)
+ fatal ("Constant attributes may not take numeric values");
+ /* Get rid of the CONST node. It is allowed only at top-level. */
+ XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
+ }
+
if (! strcmp (attr->name, "length") && ! attr->is_numeric)
fatal ("`length' attribute must take numeric values");
for (i = 0; i < XVECLEN (def, 6); i++)
orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2);
- op->busyexp = rtx_alloc (IF_THEN_ELSE);
- XEXP (op->busyexp, 0) = orexp;
- XEXP (op->busyexp, 1) = make_numeric_value (XINT (def, 5));
- XEXP (op->busyexp, 2) = make_numeric_value (0);
+ op->busyexp = attr_rtx (IF_THEN_ELSE, orexp,
+ make_numeric_value (XINT (def, 5)),
+ make_numeric_value (0));
}
else
op->busyexp = make_numeric_value (XINT (def, 5));
switch (code)
{
case SYMBOL_REF:
- /* Since this is an arbitrary expression, it can look at anything. */
- must_extract = must_constrain = 1;
+ if (! RTX_UNCHANGING_P (exp))
+ /* Since this is an arbitrary expression, it can look at anything.
+ However, constant expressions do not depend on any particular
+ insn. */
+ must_extract = must_constrain = 1;
return;
case MATCH_OPERAND:
the subroutine to use, instead of `get_attr_...'. */
if (attr->name[0] == '*')
printf ("%s (insn)\n", &attr->name[1]);
- else
+ else if (attr->is_const == 0)
printf ("get_attr_%s (insn)\n", attr->name);
+ else
+ {
+ printf ("get_attr_%s ()\n", attr->name);
+ printf ("{\n");
+
+ for (av = attr->first_value; av; av = av->next)
+ if (av->num_insns != 0)
+ write_attr_set (attr, 2, av->value, "return", ";",
+ true_rtx, av->first_insn->insn_code,
+ av->first_insn->insn_index);
+
+ printf ("}\n\n");
+ return;
+ }
printf (" rtx insn;\n");
printf ("{\n");
printf (" switch (recog_memoized (insn))\n");
testexp = eliminate_known_true (our_known_true,
XVECEXP (value, 0, i),
insn_code, insn_index);
- newexp = rtx_alloc (NOT);
- XEXP (newexp, 0) = testexp;
+ newexp = attr_rtx (NOT, testexp);
newexp = insert_right_side (AND, our_known_true, newexp,
insn_code, insn_index);
{
/* See if only one case exists and if there is a constant value for
that case. If so, we don't need a function. */
- str = (char *) xmalloc (strlen (unit->name) + 10);
+ str = (char *) alloca (strlen (unit->name) + 10);
sprintf (str, "*%s_cases", unit->name);
attr = find_attr (str, 0);
if (! attr) abort ();
for (p = *pstr; *p != ',' && *p != '\0'; p++)
;
- out_str = (char *) xmalloc (p - *pstr + 1);
- for (p = out_str; **pstr != ',' && **pstr != '\0'; (*pstr)++)
- *p++ = **pstr;
+ out_str = attr_string (*pstr, p - *pstr);
+ *pstr = p;
- *p++ = '\0';
if (**pstr == ',')
(*pstr)++;
attr = (struct attr_desc *) xmalloc (sizeof (struct attr_desc));
attr->name = new_name;
attr->first_value = attr->default_val = NULL;
- attr->is_numeric = attr->is_special = 0;
+ attr->is_numeric = attr->is_const = attr->is_special = 0;
attr->next = attrs;
attrs = attr;
abort ();
attr->is_numeric = 1;
+ attr->is_const = 0;
attr->is_special = special;
attr->default_val = get_attr_value (value, attr, -2);
}
{
static rtx int_values[20];
rtx exp;
+ char *p;
if (n < 0)
abort ();
if (n < 20 && int_values[n])
return int_values[n];
- exp = rtx_alloc (CONST_STRING);
- XSTR (exp, 0) = (char *) xmalloc ((n < 1000 ? 4
- : HOST_BITS_PER_INT * 3 / 10 + 3));
- sprintf (XSTR (exp, 0), "%d", n);
+ p = attr_printf ((n < 1000 ? 4 : HOST_BITS_PER_INT * 3 / 10 + 3), "%d", n);
+ exp = attr_rtx (CONST_STRING, p);
if (n < 20)
int_values[n] = exp;
init_rtl ();
/* Set up true and false rtx's */
- true_rtx = rtx_alloc (CONST_INT);
- false_rtx = rtx_alloc (CONST_INT);
- XINT (true_rtx, 0) = 1;
- XINT (false_rtx, 0) = 0;
+ true_rtx = attr_rtx (CONST_INT, 1);
+ false_rtx = attr_rtx (CONST_INT, 0);
RTX_UNCHANGING_P (true_rtx) = RTX_UNCHANGING_P (false_rtx) = 1;
printf ("/* Generated automatically by the program `genattrtab'\n\