#define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), unchanging))
#define ATTR_CURR_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), in_struct))
#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), return_val))
#if 0
#define strcmp_check(S1, S2) ((S1) == (S2) \
? 0 \
: (gcc_assert (strcmp ((S1), (S2))), 1))
#else
#define strcmp_check(S1, S2) ((S1) != (S2))
#endif
#include "bconfig.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "gensupport.h"
#include "obstack.h"
#include "errors.h"
#define ATTR_NONE 0
#define ATTR_SPECIAL (1 << 0)
static struct obstack obstack1, obstack2;
static struct obstack *hash_obstack = &obstack1;
static struct obstack *temp_obstack = &obstack2;
#define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
struct insn_def
{
struct insn_def *next;
rtx def;
int insn_code;
int insn_index;
int lineno;
int num_alternatives;
int vec_idx;
};
struct insn_ent
{
struct insn_ent *next;
struct insn_def *def;
};
struct attr_value
{
rtx value;
struct attr_value *next;
struct insn_ent *first_insn;
int num_insns;
int has_asm_insn;
};
struct attr_desc
{
char *name;
struct attr_desc *next;
struct attr_value *first_value;
struct attr_value *default_val;
int lineno : 24;
unsigned is_numeric : 1;
unsigned is_const : 1;
unsigned is_special : 1;
};
struct delay_desc
{
rtx def;
struct delay_desc *next;
int num;
int lineno;
};
#define MAX_ATTRS_INDEX 256
static struct attr_desc *attrs[MAX_ATTRS_INDEX];
static struct insn_def *defs;
static struct delay_desc *delays;
static int insn_code_number;
static int insn_index_number;
static int got_define_asm_attributes;
static int must_extract;
static int must_constrain;
static int address_used;
static int length_used;
static int num_delays;
static int have_annul_true, have_annul_false;
static int num_insn_ents;
static int *insn_n_alternatives;
static int *insn_alternatives;
static rtx true_rtx, false_rtx;
static const char *alternative_name;
static const char *length_str;
static const char *delay_type_str;
static const char *delay_1_0_str;
static const char *num_delay_slots_str;
#define SIMPLIFY_TEST_EXP(EXP,INSN_CODE,INSN_INDEX) \
(ATTR_IND_SIMPLIFIED_P (EXP) || ATTR_CURR_SIMPLIFIED_P (EXP) ? (EXP) \
: simplify_test_exp (EXP, INSN_CODE, INSN_INDEX))
#define DEF_ATTR_STRING(S) (attr_string ((S), strlen (S)))
static char *attr_string (const char *, int);
static char *attr_printf (unsigned int, const char *, ...)
ATTRIBUTE_PRINTF_2;
static rtx make_numeric_value (int);
static struct attr_desc *find_attr (const char **, int);
static rtx mk_attr_alt (int);
static char *next_comma_elt (const char **);
static rtx insert_right_side (enum rtx_code, rtx, rtx, int, int);
static rtx copy_boolean (rtx);
static int compares_alternatives_p (rtx);
static void make_internal_attr (const char *, rtx, int);
static void insert_insn_ent (struct attr_value *, struct insn_ent *);
static void walk_attr_value (rtx);
static int max_attr_value (rtx, int*);
static int min_attr_value (rtx, int*);
static int or_attr_value (rtx, int*);
static rtx simplify_test_exp (rtx, int, int);
static rtx simplify_test_exp_in_temp (rtx, int, int);
static rtx copy_rtx_unchanging (rtx);
static bool attr_alt_subset_p (rtx, rtx);
static bool attr_alt_subset_of_compl_p (rtx, rtx);
static void clear_struct_flag (rtx);
static void write_attr_valueq (struct attr_desc *, const char *);
static struct attr_value *find_most_used (struct attr_desc *);
static void write_attr_set (struct attr_desc *, int, rtx,
const char *, const char *, rtx,
int, int);
static void write_attr_case (struct attr_desc *, struct attr_value *,
int, const char *, const char *, int, rtx);
static void write_attr_value (struct attr_desc *, rtx);
static void write_upcase (const char *);
static void write_indent (int);
static rtx identity_fn (rtx);
static rtx zero_fn (rtx);
static rtx one_fn (rtx);
static rtx max_fn (rtx);
static rtx min_fn (rtx);
#define oballoc(size) obstack_alloc (hash_obstack, size)
struct attr_hash
{
struct attr_hash *next;
int hashcode;
union
{
char *str;
rtx rtl;
} u;
};
#define RTL_HASH_SIZE 4093
static struct attr_hash *attr_hash_table[RTL_HASH_SIZE];
#define RTL_HASH(RTL) ((long) (RTL) & 0777777)
static void
attr_hash_add_rtx (int hashcode, rtx rtl)
{
struct attr_hash *h;
h = obstack_alloc (hash_obstack, 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;
}
static void
attr_hash_add_string (int hashcode, char *str)
{
struct attr_hash *h;
h = obstack_alloc (hash_obstack, 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;
}
static rtx
attr_rtx_1 (enum rtx_code code, va_list p)
{
rtx rt_val = NULL_RTX;
int hashcode;
struct attr_hash *h;
struct obstack *old_obstack = rtl_obstack;
if (GET_RTX_CLASS (code) == RTX_UNARY)
{
rtx arg0 = va_arg (p, rtx);
if (! ATTR_PERMANENT_P (arg0))
{
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
return rt_val;
}
hashcode = ((HOST_WIDE_INT) 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)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
}
}
else if (GET_RTX_CLASS (code) == RTX_BIN_ARITH
|| GET_RTX_CLASS (code) == RTX_COMM_ARITH
|| GET_RTX_CLASS (code) == RTX_COMPARE
|| GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
{
rtx arg0 = va_arg (p, rtx);
rtx arg1 = va_arg (p, rtx);
if (! ATTR_PERMANENT_P (arg0) || ! ATTR_PERMANENT_P (arg1))
{
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
XEXP (rt_val, 1) = arg1;
return rt_val;
}
hashcode = ((HOST_WIDE_INT) 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)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
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 *);
arg0 = DEF_ATTR_STRING (arg0);
hashcode = ((HOST_WIDE_INT) 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)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
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 = ((HOST_WIDE_INT) 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)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
rt_val = rtx_alloc (code);
XSTR (rt_val, 0) = arg0;
XSTR (rt_val, 1) = arg1;
}
}
else if (code == CONST_INT)
{
HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
if (arg0 == 0)
return false_rtx;
else if (arg0 == 1)
return true_rtx;
else
goto nohash;
}
else
{
int i;
const char *fmt;
nohash:
rt_val = rtx_alloc (code);
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*fmt++)
{
case '0':
break;
case 'i':
XINT (rt_val, i) = va_arg (p, int);
break;
case 'w':
XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
break;
case 's':
XSTR (rt_val, i) = va_arg (p, char *);
break;
case 'e':
case 'u':
XEXP (rt_val, i) = va_arg (p, rtx);
break;
case 'E':
XVEC (rt_val, i) = va_arg (p, rtvec);
break;
default:
gcc_unreachable ();
}
}
return rt_val;
}
rtl_obstack = old_obstack;
attr_hash_add_rtx (hashcode, rt_val);
ATTR_PERMANENT_P (rt_val) = 1;
return rt_val;
}
static rtx
attr_rtx (enum rtx_code code, ...)
{
rtx result;
va_list p;
va_start (p, code);
result = attr_rtx_1 (code, p);
va_end (p);
return result;
}
static char *
attr_printf (unsigned int len, const char *fmt, ...)
{
char str[256];
va_list p;
va_start (p, fmt);
gcc_assert (len < sizeof str);
vsprintf (str, fmt, p);
va_end (p);
return DEF_ATTR_STRING (str);
}
static rtx
attr_eq (const char *name, const char *value)
{
return attr_rtx (EQ_ATTR, DEF_ATTR_STRING (name), DEF_ATTR_STRING (value));
}
static const char *
attr_numeral (int n)
{
return XSTR (make_numeric_value (n), 0);
}
static char *
attr_string (const char *str, int len)
{
struct attr_hash *h;
int hashcode;
int i;
char *new_str;
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;
for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
if (h->hashcode == -hashcode && h->u.str[0] == str[0]
&& !strncmp (h->u.str, str, len))
return h->u.str;
new_str = obstack_alloc (hash_obstack, len + 1);
memcpy (new_str, str, len);
new_str[len] = '\0';
attr_hash_add_string (hashcode, new_str);
return new_str;
}
static int
attr_equal_p (rtx x, rtx y)
{
return (x == y || (! (ATTR_PERMANENT_P (x) && ATTR_PERMANENT_P (y))
&& rtx_equal_p (x, y)));
}
static rtx
attr_copy_rtx (rtx orig)
{
rtx copy;
int i, j;
RTX_CODE code;
const char *format_ptr;
if (ATTR_PERMANENT_P (orig))
return orig;
code = GET_CODE (orig);
switch (code)
{
case REG:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
return orig;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
ATTR_IND_SIMPLIFIED_P (copy) = ATTR_IND_SIMPLIFIED_P (orig);
ATTR_CURR_SIMPLIFIED_P (copy) = ATTR_CURR_SIMPLIFIED_P (orig);
ATTR_PERMANENT_P (copy) = ATTR_PERMANENT_P (orig);
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = attr_copy_rtx (XEXP (orig, i));
break;
case 'E':
case 'V':
XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = attr_copy_rtx (XVECEXP (orig, i, j));
}
break;
case 'n':
case 'i':
XINT (copy, i) = XINT (orig, i);
break;
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
case 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
default:
gcc_unreachable ();
}
}
return copy;
}
static rtx
check_attr_test (rtx exp, int is_const, int lineno)
{
struct attr_desc *attr;
struct attr_value *av;
const char *name_ptr, *p;
rtx orexp, newexp;
switch (GET_CODE (exp))
{
case EQ_ATTR:
if (XSTR (exp, 1)[0] == '!')
return check_attr_test (attr_rtx (NOT,
attr_eq (XSTR (exp, 0),
&XSTR (exp, 1)[1])),
is_const, lineno);
else if (n_comma_elts (XSTR (exp, 1)) == 1)
{
attr = find_attr (&XSTR (exp, 0), 0);
if (attr == NULL)
{
if (! strcmp (XSTR (exp, 0), "alternative"))
return mk_attr_alt (1 << atoi (XSTR (exp, 1)));
else
fatal ("unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0));
}
if (is_const && ! attr->is_const)
fatal ("constant expression uses insn attribute `%s' in EQ_ATTR",
XSTR (exp, 0));
exp = attr_eq (XSTR (exp, 0), XSTR (exp, 1));
if (attr->is_const)
ATTR_IND_SIMPLIFIED_P (exp) = 1;
if (attr->is_numeric)
{
for (p = XSTR (exp, 1); *p; p++)
if (! ISDIGIT (*p))
fatal ("attribute `%s' takes only numeric values",
XSTR (exp, 0));
}
else
{
for (av = attr->first_value; av; av = av->next)
if (GET_CODE (av->value) == CONST_STRING
&& ! strcmp (XSTR (exp, 1), XSTR (av->value, 0)))
break;
if (av == NULL)
fatal ("unknown value `%s' for `%s' attribute",
XSTR (exp, 1), XSTR (exp, 0));
}
}
else
{
if (! strcmp (XSTR (exp, 0), "alternative"))
{
int set = 0;
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
set |= 1 << atoi (p);
return mk_attr_alt (set);
}
else
{
orexp = false_rtx;
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
newexp = attr_eq (XSTR (exp, 0), p);
orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
}
return check_attr_test (orexp, is_const, lineno);
}
}
break;
case ATTR_FLAG:
break;
case CONST_INT:
if (XWINT (exp, 0))
return true_rtx;
else
return false_rtx;
case IOR:
case AND:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
XEXP (exp, 1) = check_attr_test (XEXP (exp, 1), is_const, lineno);
break;
case NOT:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
break;
case MATCH_OPERAND:
if (is_const)
fatal ("RTL operator \"%s\" not valid in constant attribute test",
GET_RTX_NAME (GET_CODE (exp)));
ATTR_IND_SIMPLIFIED_P (exp) = 1;
break;
case LE: case LT: case GT: case GE:
case LEU: case LTU: case GTU: case GEU:
case NE: case EQ:
if (GET_CODE (XEXP (exp, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (exp, 1)) == SYMBOL_REF)
exp = attr_rtx (GET_CODE (exp),
attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 0), 0)),
attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 1), 0)));
ATTR_IND_SIMPLIFIED_P (exp) = 1;
break;
case SYMBOL_REF:
if (is_const)
{
exp = attr_rtx (SYMBOL_REF, XSTR (exp, 0));
ATTR_IND_SIMPLIFIED_P (exp) = 1;
break;
}
default:
fatal ("RTL operator \"%s\" not valid in attribute test",
GET_RTX_NAME (GET_CODE (exp)));
}
return exp;
}
static rtx
check_attr_value (rtx exp, struct attr_desc *attr)
{
struct attr_value *av;
const char *p;
int i;
switch (GET_CODE (exp))
{
case CONST_INT:
if (attr && ! attr->is_numeric)
{
message_with_line (attr->lineno,
"CONST_INT not valid for non-numeric attribute %s",
attr->name);
have_error = 1;
break;
}
if (INTVAL (exp) < 0)
{
message_with_line (attr->lineno,
"negative numeric value specified for attribute %s",
attr->name);
have_error = 1;
break;
}
break;
case CONST_STRING:
if (! strcmp (XSTR (exp, 0), "*"))
break;
if (attr == 0 || attr->is_numeric)
{
p = XSTR (exp, 0);
for (; *p; p++)
if (! ISDIGIT (*p))
{
message_with_line (attr ? attr->lineno : 0,
"non-numeric value for numeric attribute %s",
attr ? attr->name : "internal");
have_error = 1;
break;
}
break;
}
for (av = attr->first_value; av; av = av->next)
if (GET_CODE (av->value) == CONST_STRING
&& ! strcmp (XSTR (av->value, 0), XSTR (exp, 0)))
break;
if (av == NULL)
{
message_with_line (attr->lineno,
"unknown value `%s' for `%s' attribute",
XSTR (exp, 0), attr ? attr->name : "internal");
have_error = 1;
}
break;
case IF_THEN_ELSE:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0),
attr ? attr->is_const : 0,
attr ? attr->lineno : 0);
XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
break;
case PLUS:
case MINUS:
case MULT:
case DIV:
case MOD:
if (attr && !attr->is_numeric)
{
message_with_line (attr->lineno,
"invalid operation `%s' for non-numeric attribute value",
GET_RTX_NAME (GET_CODE (exp)));
have_error = 1;
break;
}
case IOR:
case AND:
XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
break;
case FFS:
case CLZ:
case CTZ:
case POPCOUNT:
case PARITY:
XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
break;
case COND:
if (XVECLEN (exp, 0) % 2 != 0)
{
message_with_line (attr->lineno,
"first operand of COND must have even length");
have_error = 1;
break;
}
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i),
attr ? attr->is_const : 0,
attr ? attr->lineno : 0);
XVECEXP (exp, 0, i + 1)
= check_attr_value (XVECEXP (exp, 0, i + 1), attr);
}
XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
break;
case ATTR:
{
struct attr_desc *attr2 = find_attr (&XSTR (exp, 0), 0);
if (attr2 == NULL)
{
message_with_line (attr ? attr->lineno : 0,
"unknown attribute `%s' in ATTR",
XSTR (exp, 0));
have_error = 1;
}
else if (attr && attr->is_const && ! attr2->is_const)
{
message_with_line (attr->lineno,
"non-constant attribute `%s' referenced from `%s'",
XSTR (exp, 0), attr->name);
have_error = 1;
}
else if (attr
&& attr->is_numeric != attr2->is_numeric)
{
message_with_line (attr->lineno,
"numeric attribute mismatch calling `%s' from `%s'",
XSTR (exp, 0), attr->name);
have_error = 1;
}
}
break;
case SYMBOL_REF:
return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
default:
message_with_line (attr ? attr->lineno : 0,
"invalid operation `%s' for attribute value",
GET_RTX_NAME (GET_CODE (exp)));
have_error = 1;
break;
}
return exp;
}
static rtx
convert_set_attr_alternative (rtx exp, struct insn_def *id)
{
int num_alt = id->num_alternatives;
rtx condexp;
int i;
if (XVECLEN (exp, 1) != num_alt)
{
message_with_line (id->lineno,
"bad number of entries in SET_ATTR_ALTERNATIVE");
have_error = 1;
return NULL_RTX;
}
condexp = rtx_alloc (COND);
XVEC (condexp, 0) = rtvec_alloc ((num_alt - 1) * 2);
for (i = 0; i < num_alt - 1; i++)
{
const char *p;
p = attr_numeral (i);
XVECEXP (condexp, 0, 2 * i) = attr_eq (alternative_name, p);
XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP (exp, 1, i);
}
XEXP (condexp, 1) = XVECEXP (exp, 1, i);
return attr_rtx (SET, attr_rtx (ATTR, XSTR (exp, 0)), condexp);
}
static rtx
convert_set_attr (rtx exp, struct insn_def *id)
{
rtx newexp;
const char *name_ptr;
char *p;
int n;
n = n_comma_elts (XSTR (exp, 1));
if (n == 1)
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);
XVEC (newexp, 1) = rtvec_alloc (n);
name_ptr = XSTR (exp, 1);
n = 0;
while ((p = next_comma_elt (&name_ptr)) != NULL)
XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
return convert_set_attr_alternative (newexp, id);
}
static void
check_defs (void)
{
struct insn_def *id;
struct attr_desc *attr;
int i;
rtx value;
for (id = defs; id; id = id->next)
{
if (XVEC (id->def, id->vec_idx) == NULL)
continue;
for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
{
value = XVECEXP (id->def, id->vec_idx, i);
switch (GET_CODE (value))
{
case SET:
if (GET_CODE (XEXP (value, 0)) != ATTR)
{
message_with_line (id->lineno, "bad attribute set");
have_error = 1;
value = NULL_RTX;
}
break;
case SET_ATTR_ALTERNATIVE:
value = convert_set_attr_alternative (value, id);
break;
case SET_ATTR:
value = convert_set_attr (value, id);
break;
default:
message_with_line (id->lineno, "invalid attribute code %s",
GET_RTX_NAME (GET_CODE (value)));
have_error = 1;
value = NULL_RTX;
}
if (value == NULL_RTX)
continue;
if ((attr = find_attr (&XSTR (XEXP (value, 0), 0), 0)) == NULL)
{
message_with_line (id->lineno, "unknown attribute %s",
XSTR (XEXP (value, 0), 0));
have_error = 1;
continue;
}
XVECEXP (id->def, id->vec_idx, i) = value;
XEXP (value, 1) = check_attr_value (XEXP (value, 1), attr);
}
}
}
static rtx
make_canonical (struct attr_desc *attr, rtx exp)
{
int i;
rtx newexp;
switch (GET_CODE (exp))
{
case CONST_INT:
exp = make_numeric_value (INTVAL (exp));
break;
case CONST_STRING:
if (! strcmp (XSTR (exp, 0), "*"))
{
if (attr == 0 || attr->default_val == 0)
fatal ("(attr_value \"*\") used in invalid context");
exp = attr->default_val->value;
}
else
XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
break;
case SYMBOL_REF:
if (!attr->is_const || ATTR_IND_SIMPLIFIED_P (exp))
break;
ATTR_IND_SIMPLIFIED_P (exp) = 1;
exp = check_attr_value (exp, attr);
break;
case IF_THEN_ELSE:
newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (2);
XVECEXP (newexp, 0, 0) = XEXP (exp, 0);
XVECEXP (newexp, 0, 1) = XEXP (exp, 1);
XEXP (newexp, 1) = XEXP (exp, 2);
exp = newexp;
case COND:
{
int allsame = 1;
rtx defval;
if (XVECLEN (exp, 0) == 0)
return make_canonical (attr, XEXP (exp, 1));
defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
XVECEXP (exp, 0, i) = copy_boolean (XVECEXP (exp, 0, i));
XVECEXP (exp, 0, i + 1)
= make_canonical (attr, XVECEXP (exp, 0, i + 1));
if (! rtx_equal_p (XVECEXP (exp, 0, i + 1), defval))
allsame = 0;
}
if (allsame)
return defval;
}
break;
default:
break;
}
return exp;
}
static rtx
copy_boolean (rtx exp)
{
if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR)
return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)),
copy_boolean (XEXP (exp, 1)));
if (GET_CODE (exp) == MATCH_OPERAND)
{
XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
XSTR (exp, 2) = DEF_ATTR_STRING (XSTR (exp, 2));
}
else if (GET_CODE (exp) == EQ_ATTR)
{
XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
}
return exp;
}
static struct attr_value *
get_attr_value (rtx value, struct attr_desc *attr, int insn_code)
{
struct attr_value *av;
int num_alt = 0;
value = make_canonical (attr, value);
if (compares_alternatives_p (value))
{
if (insn_code < 0 || insn_alternatives == NULL)
fatal ("(eq_attr \"alternatives\" ...) used in non-insn context");
else
num_alt = insn_alternatives[insn_code];
}
for (av = attr->first_value; av; av = av->next)
if (rtx_equal_p (value, av->value)
&& (num_alt == 0 || av->first_insn == NULL
|| insn_alternatives[av->first_insn->def->insn_code]))
return av;
av = oballoc (sizeof (struct attr_value));
av->value = value;
av->next = attr->first_value;
attr->first_value = av;
av->first_insn = NULL;
av->num_insns = 0;
av->has_asm_insn = 0;
return av;
}
static void
expand_delays (void)
{
struct delay_desc *delay;
rtx condexp;
rtx newexp;
int i;
char *p;
condexp = rtx_alloc (COND);
XVEC (condexp, 0) = rtvec_alloc (num_delays * 2);
XEXP (condexp, 1) = make_numeric_value (0);
for (i = 0, delay = delays; delay; i += 2, delay = delay->next)
{
XVECEXP (condexp, 0, i) = XEXP (delay->def, 0);
XVECEXP (condexp, 0, i + 1)
= make_numeric_value (XVECLEN (delay->def, 1) / 3);
}
make_internal_attr (num_delay_slots_str, condexp, ATTR_NONE);
if (num_delays > 1)
{
condexp = rtx_alloc (COND);
XVEC (condexp, 0) = rtvec_alloc (num_delays * 2);
XEXP (condexp, 1) = make_numeric_value (0);
for (i = 0, delay = delays; delay; i += 2, delay = delay->next)
{
XVECEXP (condexp, 0, i) = XEXP (delay->def, 0);
XVECEXP (condexp, 0, i + 1) = make_numeric_value (delay->num);
}
make_internal_attr (delay_type_str, condexp, ATTR_SPECIAL);
}
for (delay = delays; delay; delay = delay->next)
{
for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
{
condexp = XVECEXP (delay->def, 1, i);
if (condexp == 0)
condexp = false_rtx;
newexp = attr_rtx (IF_THEN_ELSE, condexp,
make_numeric_value (1), make_numeric_value (0));
p = attr_printf (sizeof "*delay__" + MAX_DIGITS * 2,
"*delay_%d_%d", delay->num, i / 3);
make_internal_attr (p, newexp, ATTR_SPECIAL);
if (have_annul_true)
{
condexp = XVECEXP (delay->def, 1, i + 1);
if (condexp == 0) condexp = false_rtx;
newexp = attr_rtx (IF_THEN_ELSE, condexp,
make_numeric_value (1),
make_numeric_value (0));
p = attr_printf (sizeof "*annul_true__" + MAX_DIGITS * 2,
"*annul_true_%d_%d", delay->num, i / 3);
make_internal_attr (p, newexp, ATTR_SPECIAL);
}
if (have_annul_false)
{
condexp = XVECEXP (delay->def, 1, i + 2);
if (condexp == 0) condexp = false_rtx;
newexp = attr_rtx (IF_THEN_ELSE, condexp,
make_numeric_value (1),
make_numeric_value (0));
p = attr_printf (sizeof "*annul_false__" + MAX_DIGITS * 2,
"*annul_false_%d_%d", delay->num, i / 3);
make_internal_attr (p, newexp, ATTR_SPECIAL);
}
}
}
}
static void
fill_attr (struct attr_desc *attr)
{
struct attr_value *av;
struct insn_ent *ie;
struct insn_def *id;
int i;
rtx value;
if (attr->is_const)
return;
for (id = defs; id; id = id->next)
{
value = NULL;
if (XVEC (id->def, id->vec_idx))
for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
if (! strcmp_check (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0),
attr->name))
value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1);
if (value == NULL)
av = attr->default_val;
else
av = get_attr_value (value, attr, id->insn_code);
ie = oballoc (sizeof (struct insn_ent));
ie->def = id;
insert_insn_ent (av, ie);
}
}
static rtx
substitute_address (rtx exp, rtx (*no_address_fn) (rtx),
rtx (*address_fn) (rtx))
{
int i;
rtx newexp;
if (GET_CODE (exp) == COND)
{
address_used = 0;
for (i = 0; i < XVECLEN (exp, 0); i += 2)
walk_attr_value (XVECEXP (exp, 0, i));
if (address_used)
return (*address_fn) (exp);
newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
XVECEXP (newexp, 0, i + 1)
= substitute_address (XVECEXP (exp, 0, i + 1),
no_address_fn, address_fn);
}
XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
no_address_fn, address_fn);
return newexp;
}
else if (GET_CODE (exp) == IF_THEN_ELSE)
{
address_used = 0;
walk_attr_value (XEXP (exp, 0));
if (address_used)
return (*address_fn) (exp);
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);
}
static void
make_length_attrs (void)
{
static const char *new_names[] =
{
"*insn_default_length",
"*insn_min_length",
"*insn_variable_length_p",
"*insn_current_length"
};
static rtx (*const no_address_fn[]) (rtx)
= {identity_fn,identity_fn, zero_fn, zero_fn};
static rtx (*const address_fn[]) (rtx)
= {max_fn, min_fn, one_fn, identity_fn};
size_t i;
struct attr_desc *length_attr, *new_attr;
struct attr_value *av, *new_av;
struct insn_ent *ie, *new_ie;
length_attr = find_attr (&length_str, 0);
if (length_attr == 0)
return;
if (! length_attr->is_numeric)
fatal ("length attribute must be numeric");
length_attr->is_const = 0;
length_attr->is_special = 1;
for (i = 0; i < ARRAY_SIZE (new_names); i++)
{
make_internal_attr (new_names[i],
substitute_address (length_attr->default_val->value,
no_address_fn[i], address_fn[i]),
ATTR_NONE);
new_attr = find_attr (&new_names[i], 0);
for (av = length_attr->first_value; av; av = av->next)
for (ie = av->first_insn; ie; ie = ie->next)
{
new_av = get_attr_value (substitute_address (av->value,
no_address_fn[i],
address_fn[i]),
new_attr, ie->def->insn_code);
new_ie = oballoc (sizeof (struct insn_ent));
new_ie->def = ie->def;
insert_insn_ent (new_av, new_ie);
}
}
}
static rtx
identity_fn (rtx exp)
{
return exp;
}
static rtx
zero_fn (rtx exp ATTRIBUTE_UNUSED)
{
return make_numeric_value (0);
}
static rtx
one_fn (rtx exp ATTRIBUTE_UNUSED)
{
return make_numeric_value (1);
}
static rtx
max_fn (rtx exp)
{
int unknown;
return make_numeric_value (max_attr_value (exp, &unknown));
}
static rtx
min_fn (rtx exp)
{
int unknown;
return make_numeric_value (min_attr_value (exp, &unknown));
}
static void
write_length_unit_log (void)
{
struct attr_desc *length_attr = find_attr (&length_str, 0);
struct attr_value *av;
struct insn_ent *ie;
unsigned int length_unit_log, length_or;
int unknown = 0;
if (length_attr == 0)
return;
length_or = or_attr_value (length_attr->default_val->value, &unknown);
for (av = length_attr->first_value; av; av = av->next)
for (ie = av->first_insn; ie; ie = ie->next)
length_or |= or_attr_value (av->value, &unknown);
if (unknown)
length_unit_log = 0;
else
{
length_or = ~length_or;
for (length_unit_log = 0; length_or & 1; length_or >>= 1)
length_unit_log++;
}
printf ("const int length_unit_log = %u;\n", length_unit_log);
}
static rtx
simplify_cond (rtx exp, int insn_code, int insn_index)
{
int i, j;
rtx defval = XEXP (exp, 1);
rtx new_defval = XEXP (exp, 1);
int len = XVECLEN (exp, 0);
rtx *tests = XNEWVEC (rtx, len);
int allsame = 1;
rtx ret;
obstack_finish (rtl_obstack);
memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
if (GET_CODE (defval) == COND)
new_defval = simplify_cond (defval, insn_code, insn_index);
for (i = 0; i < len; i += 2)
{
rtx newtest, newval;
newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
tests[i] = newtest;
newval = tests[i + 1];
if (GET_CODE (newval) == COND)
newval = simplify_cond (newval, insn_code, insn_index);
if (newtest == true_rtx)
{
len = i;
defval = tests[i + 1];
new_defval = newval;
}
else if (newtest == false_rtx)
{
for (j = i; j < len - 2; j++)
tests[j] = tests[j + 2];
i -= 2;
len -= 2;
}
else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
{
tests[i - 2]
= insert_right_side (IOR, tests[i - 2], newtest,
insn_code, insn_index);
for (j = i; j < len - 2; j++)
tests[j] = tests[j + 2];
len -= 2;
i -= 2;
}
else
tests[i + 1] = newval;
}
while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
len -= 2;
if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1))
allsame = 0;
else
for (i = 0; i < len; i++)
if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
{
allsame = 0;
break;
}
if (len == 0)
{
if (GET_CODE (defval) == COND)
ret = simplify_cond (defval, insn_code, insn_index);
else
ret = defval;
}
else if (allsame)
ret = exp;
else
{
rtx newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (len);
memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx));
XEXP (newexp, 1) = new_defval;
ret = newexp;
}
free (tests);
return ret;
}
static void
remove_insn_ent (struct attr_value *av, struct insn_ent *ie)
{
struct insn_ent *previe;
if (av->first_insn == ie)
av->first_insn = ie->next;
else
{
for (previe = av->first_insn; previe->next != ie; previe = previe->next)
;
previe->next = ie->next;
}
av->num_insns--;
if (ie->def->insn_code == -1)
av->has_asm_insn = 0;
num_insn_ents--;
}
static void
insert_insn_ent (struct attr_value *av, struct insn_ent *ie)
{
ie->next = av->first_insn;
av->first_insn = ie;
av->num_insns++;
if (ie->def->insn_code == -1)
av->has_asm_insn = 1;
num_insn_ents++;
}
static rtx
insert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index)
{
rtx newexp;
if (code == AND && term == true_rtx)
return exp;
if (code == AND && term == false_rtx)
return false_rtx;
if (code == AND && exp == true_rtx)
return term;
if (code == AND && exp == false_rtx)
return false_rtx;
if (code == IOR && term == true_rtx)
return true_rtx;
if (code == IOR && term == false_rtx)
return exp;
if (code == IOR && exp == true_rtx)
return true_rtx;
if (code == IOR && exp == false_rtx)
return term;
if (attr_equal_p (exp, term))
return exp;
if (GET_CODE (term) == code)
{
exp = insert_right_side (code, exp, XEXP (term, 0),
insn_code, insn_index);
exp = insert_right_side (code, exp, XEXP (term, 1),
insn_code, insn_index);
return exp;
}
if (GET_CODE (exp) == code)
{
rtx new = insert_right_side (code, XEXP (exp, 1),
term, insn_code, insn_index);
if (new != XEXP (exp, 1))
newexp = attr_rtx (code, XEXP (exp, 0), new);
else
newexp = exp;
}
else
{
newexp = attr_rtx (code, exp, term);
}
return simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
static int
compute_alternative_mask (rtx exp, enum rtx_code code)
{
const char *string;
if (GET_CODE (exp) == code)
return compute_alternative_mask (XEXP (exp, 0), code)
| compute_alternative_mask (XEXP (exp, 1), code);
else if (code == AND && GET_CODE (exp) == NOT
&& GET_CODE (XEXP (exp, 0)) == EQ_ATTR
&& XSTR (XEXP (exp, 0), 0) == alternative_name)
string = XSTR (XEXP (exp, 0), 1);
else if (code == IOR && GET_CODE (exp) == EQ_ATTR
&& XSTR (exp, 0) == alternative_name)
string = XSTR (exp, 1);
else if (GET_CODE (exp) == EQ_ATTR_ALT)
{
if (code == AND && XINT (exp, 1))
return XINT (exp, 0);
if (code == IOR && !XINT (exp, 1))
return XINT (exp, 0);
return 0;
}
else
return 0;
if (string[1] == 0)
return 1 << (string[0] - '0');
return 1 << atoi (string);
}
static rtx
make_alternative_compare (int mask)
{
return mk_attr_alt (mask);
}
static rtx
evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index)
{
rtx orexp, andexp;
rtx right;
rtx newexp;
int i;
switch (GET_CODE (value))
{
case CONST_STRING:
if (! strcmp_check (XSTR (value, 0), XSTR (exp, 1)))
newexp = true_rtx;
else
newexp = false_rtx;
break;
case SYMBOL_REF:
{
char *p;
char string[256];
gcc_assert (GET_CODE (exp) == EQ_ATTR);
gcc_assert (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2
<= 256);
strcpy (string, XSTR (exp, 0));
strcat (string, "_");
strcat (string, XSTR (exp, 1));
for (p = string; *p; p++)
*p = TOUPPER (*p);
newexp = attr_rtx (EQ, value,
attr_rtx (SYMBOL_REF,
DEF_ATTR_STRING (string)));
break;
}
case COND:
orexp = false_rtx;
andexp = true_rtx;
for (i = 0; i < XVECLEN (value, 0); i += 2)
{
rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i),
insn_code, insn_index);
right = insert_right_side (AND, andexp, this,
insn_code, insn_index);
right = insert_right_side (AND, right,
evaluate_eq_attr (exp,
XVECEXP (value, 0,
i + 1),
insn_code, insn_index),
insn_code, insn_index);
orexp = insert_right_side (IOR, orexp, right,
insn_code, insn_index);
newexp = attr_rtx (NOT, this);
andexp = insert_right_side (AND, andexp, newexp,
insn_code, insn_index);
}
right = insert_right_side (AND, andexp,
evaluate_eq_attr (exp, XEXP (value, 1),
insn_code, insn_index),
insn_code, insn_index);
newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
break;
default:
gcc_unreachable ();
}
address_used = 0;
walk_attr_value (newexp);
if (address_used)
{
if (! ATTR_IND_SIMPLIFIED_P (exp))
return copy_rtx_unchanging (exp);
return exp;
}
else
return newexp;
}
static rtx
simplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
{
rtx left, right;
rtx newexp;
rtx temp;
int left_eliminates_term, right_eliminates_term;
if (GET_CODE (exp) == AND)
{
left = simplify_and_tree (XEXP (exp, 0), pterm, 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 = attr_rtx (AND, left, right);
exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
}
else if (GET_CODE (exp) == IOR)
{
temp = *pterm;
left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
left_eliminates_term = (temp == true_rtx);
temp = *pterm;
right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
right_eliminates_term = (temp == true_rtx);
if (left_eliminates_term && right_eliminates_term)
*pterm = true_rtx;
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
newexp = attr_rtx (IOR, left, right);
exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
}
if (exp == *pterm)
return true_rtx;
else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm)
return false_rtx;
else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0))
return false_rtx;
else if (GET_CODE (exp) == EQ_ATTR_ALT && GET_CODE (*pterm) == EQ_ATTR_ALT)
{
if (attr_alt_subset_p (*pterm, exp))
return true_rtx;
if (attr_alt_subset_of_compl_p (*pterm, exp))
return false_rtx;
if (attr_alt_subset_p (exp, *pterm))
*pterm = true_rtx;
return exp;
}
else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR)
{
if (XSTR (exp, 0) != XSTR (*pterm, 0))
return exp;
if (! strcmp_check (XSTR (exp, 1), XSTR (*pterm, 1)))
return true_rtx;
else
return false_rtx;
}
else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
&& GET_CODE (XEXP (exp, 0)) == EQ_ATTR)
{
if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0))
return exp;
if (! strcmp_check (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1)))
return false_rtx;
else
return true_rtx;
}
else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
&& GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR)
{
if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0))
return exp;
if (! strcmp_check (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1)))
return false_rtx;
else
*pterm = true_rtx;
}
else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT)
{
if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0)))
return true_rtx;
}
else if (GET_CODE (exp) == NOT)
{
if (attr_equal_p (XEXP (exp, 0), *pterm))
return false_rtx;
}
else if (GET_CODE (*pterm) == NOT)
{
if (attr_equal_p (XEXP (*pterm, 0), exp))
return false_rtx;
}
else if (attr_equal_p (exp, *pterm))
return true_rtx;
return exp;
}
static rtx
simplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
{
rtx left, right;
rtx newexp;
rtx temp;
int left_eliminates_term, right_eliminates_term;
if (GET_CODE (exp) == IOR)
{
left = simplify_or_tree (XEXP (exp, 0), pterm, 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 = attr_rtx (GET_CODE (exp), left, right);
exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
}
else if (GET_CODE (exp) == AND)
{
temp = *pterm;
left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
left_eliminates_term = (temp == false_rtx);
temp = *pterm;
right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
right_eliminates_term = (temp == false_rtx);
if (left_eliminates_term && right_eliminates_term)
*pterm = false_rtx;
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
newexp = attr_rtx (GET_CODE (exp), left, right);
exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
}
if (attr_equal_p (exp, *pterm))
return false_rtx;
else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm))
return true_rtx;
else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp))
return true_rtx;
else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
&& GET_CODE (XEXP (exp, 0)) == EQ_ATTR
&& XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0))
*pterm = false_rtx;
else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
&& GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR
&& XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0))
return false_rtx;
return exp;
}
static int
attr_rtx_cost (rtx x)
{
int cost = 0;
enum rtx_code code;
if (!x)
return 0;
code = GET_CODE (x);
switch (code)
{
case MATCH_OPERAND:
if (XSTR (x, 1)[0])
return 10;
else
return 0;
case EQ_ATTR_ALT:
return 0;
case EQ_ATTR:
if (!strcmp_check (XSTR (x, 0), alternative_name))
return 0;
else
return 5;
default:
{
int i, j;
const char *fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'V':
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
cost += attr_rtx_cost (XVECEXP (x, i, j));
break;
case 'e':
cost += attr_rtx_cost (XEXP (x, i));
break;
}
}
}
break;
}
return cost;
}
static rtx
simplify_test_exp_in_temp (rtx exp, int insn_code, int insn_index)
{
rtx x;
struct obstack *old;
if (ATTR_IND_SIMPLIFIED_P (exp))
return exp;
old = rtl_obstack;
rtl_obstack = temp_obstack;
x = simplify_test_exp (exp, insn_code, insn_index);
rtl_obstack = old;
if (x == exp || rtl_obstack == temp_obstack)
return x;
return attr_copy_rtx (x);
}
static bool
attr_alt_subset_p (rtx s1, rtx s2)
{
switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
{
case (0 << 1) | 0:
return !(XINT (s1, 0) &~ XINT (s2, 0));
case (0 << 1) | 1:
return !(XINT (s1, 0) & XINT (s2, 0));
case (1 << 1) | 0:
return false;
case (1 << 1) | 1:
return !(XINT (s2, 0) &~ XINT (s1, 0));
default:
gcc_unreachable ();
}
}
static bool
attr_alt_subset_of_compl_p (rtx s1, rtx s2)
{
switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
{
case (0 << 1) | 0:
return !(XINT (s1, 0) & XINT (s2, 0));
case (0 << 1) | 1:
return !(XINT (s1, 0) & ~XINT (s2, 0));
case (1 << 1) | 0:
return !(XINT (s2, 0) &~ XINT (s1, 0));
case (1 << 1) | 1:
return false;
default:
gcc_unreachable ();
}
}
static rtx
attr_alt_intersection (rtx s1, rtx s2)
{
rtx result = rtx_alloc (EQ_ATTR_ALT);
switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
{
case (0 << 1) | 0:
XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
break;
case (0 << 1) | 1:
XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
break;
case (1 << 1) | 0:
XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
break;
case (1 << 1) | 1:
XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
break;
default:
gcc_unreachable ();
}
XINT (result, 1) = XINT (s1, 1) & XINT (s2, 1);
return result;
}
static rtx
attr_alt_union (rtx s1, rtx s2)
{
rtx result = rtx_alloc (EQ_ATTR_ALT);
switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
{
case (0 << 1) | 0:
XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
break;
case (0 << 1) | 1:
XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
break;
case (1 << 1) | 0:
XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
break;
case (1 << 1) | 1:
XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
break;
default:
gcc_unreachable ();
}
XINT (result, 1) = XINT (s1, 1) | XINT (s2, 1);
return result;
}
static rtx
attr_alt_complement (rtx s)
{
rtx result = rtx_alloc (EQ_ATTR_ALT);
XINT (result, 0) = XINT (s, 0);
XINT (result, 1) = 1 - XINT (s, 1);
return result;
}
static rtx
mk_attr_alt (int e)
{
rtx result = rtx_alloc (EQ_ATTR_ALT);
XINT (result, 0) = e;
XINT (result, 1) = 0;
return result;
}
static rtx
simplify_test_exp (rtx exp, int insn_code, int insn_index)
{
rtx left, right;
struct attr_desc *attr;
struct attr_value *av;
struct insn_ent *ie;
int i;
rtx newexp = exp;
bool left_alt, right_alt;
if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp))
return exp;
switch (GET_CODE (exp))
{
case AND:
left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
if (left == false_rtx)
return false_rtx;
right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
if (right == false_rtx)
return false_rtx;
if (GET_CODE (left) == EQ_ATTR_ALT
&& GET_CODE (right) == EQ_ATTR_ALT)
{
exp = attr_alt_intersection (left, right);
return simplify_test_exp (exp, insn_code, insn_index);
}
if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR)
&& compute_alternative_mask (left, IOR)
&& compute_alternative_mask (right, IOR))
{
if (GET_CODE (left) == IOR)
{
rtx tem = left;
left = right;
right = tem;
}
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);
}
right = simplify_and_tree (right, &left, insn_code, insn_index);
if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
left = simplify_and_tree (left, &right, insn_code, insn_index);
if (left == false_rtx || right == false_rtx)
return false_rtx;
else if (left == true_rtx)
{
return right;
}
else if (right == true_rtx)
{
return left;
}
if (GET_CODE (left) == NOT)
left_alt = (GET_CODE (XEXP (left, 0)) == EQ_ATTR
&& XSTR (XEXP (left, 0), 0) == alternative_name);
else
left_alt = (GET_CODE (left) == EQ_ATTR_ALT
&& XINT (left, 1));
if (GET_CODE (right) == NOT)
right_alt = (GET_CODE (XEXP (right, 0)) == EQ_ATTR
&& XSTR (XEXP (right, 0), 0) == alternative_name);
else
right_alt = (GET_CODE (right) == EQ_ATTR_ALT
&& XINT (right, 1));
if (insn_code >= 0
&& (GET_CODE (left) == AND
|| left_alt
|| GET_CODE (right) == AND
|| right_alt))
{
i = compute_alternative_mask (exp, AND);
if (i & ~insn_alternatives[insn_code])
fatal ("invalid alternative specified for pattern number %d",
insn_index);
i ^= insn_alternatives[insn_code];
if (i == 0)
return false_rtx;
else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
{
left = make_alternative_compare (i);
right = simplify_and_tree (exp, &left, insn_code, insn_index);
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 = attr_rtx (AND, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
break;
case IOR:
left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
if (left == true_rtx)
return true_rtx;
right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
if (right == true_rtx)
return true_rtx;
if (GET_CODE (left) == EQ_ATTR_ALT
&& GET_CODE (right) == EQ_ATTR_ALT)
{
exp = attr_alt_union (left, right);
return simplify_test_exp (exp, insn_code, insn_index);
}
right = simplify_or_tree (right, &left, insn_code, insn_index);
if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
left = simplify_or_tree (left, &right, insn_code, insn_index);
if (right == true_rtx || left == true_rtx)
return true_rtx;
else if (left == false_rtx)
{
return right;
}
else if (right == false_rtx)
{
return left;
}
else if (GET_CODE (left) == AND && GET_CODE (right) == AND
&& attr_equal_p (XEXP (left, 0), XEXP (right, 0)))
{
newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1));
left = XEXP (left, 0);
right = newexp;
newexp = attr_rtx (AND, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
else if (insn_code >= 0
&& (GET_CODE (left) == IOR
|| (GET_CODE (left) == EQ_ATTR_ALT
&& !XINT (left, 1))
|| (GET_CODE (left) == EQ_ATTR
&& XSTR (left, 0) == alternative_name)
|| GET_CODE (right) == IOR
|| (GET_CODE (right) == EQ_ATTR_ALT
&& !XINT (right, 1))
|| (GET_CODE (right) == EQ_ATTR
&& XSTR (right, 0) == alternative_name)))
{
i = compute_alternative_mask (exp, IOR);
if (i & ~insn_alternatives[insn_code])
fatal ("invalid alternative specified for pattern number %d",
insn_index);
i ^= insn_alternatives[insn_code];
if (i == 0)
return true_rtx;
else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
{
left = make_alternative_compare (i);
right = simplify_and_tree (exp, &left, insn_code, insn_index);
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 = attr_rtx (IOR, left, right);
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
}
break;
case NOT:
if (GET_CODE (XEXP (exp, 0)) == NOT)
{
left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0),
insn_code, insn_index);
return left;
}
left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
if (GET_CODE (left) == NOT)
return XEXP (left, 0);
if (left == false_rtx)
return true_rtx;
if (left == true_rtx)
return false_rtx;
if (GET_CODE (left) == EQ_ATTR_ALT)
{
exp = attr_alt_complement (left);
return simplify_test_exp (exp, insn_code, insn_index);
}
if (GET_CODE (left) == IOR)
{
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 = 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 = attr_rtx (NOT, left);
}
break;
case EQ_ATTR_ALT:
if (!XINT (exp, 0))
return XINT (exp, 1) ? true_rtx : false_rtx;
break;
case EQ_ATTR:
if (XSTR (exp, 0) == alternative_name)
{
newexp = mk_attr_alt (1 << atoi (XSTR (exp, 1)));
break;
}
if (insn_code >= 0
&& (attr = find_attr (&XSTR (exp, 0), 0)) != NULL)
for (av = attr->first_value; av; av = av->next)
for (ie = av->first_insn; ie; ie = ie->next)
if (ie->def->insn_code == insn_code)
{
rtx x;
x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
if (attr_rtx_cost(x) < 20)
return x;
}
break;
default:
break;
}
if (insn_code != -2
&& ! ATTR_IND_SIMPLIFIED_P (newexp))
return copy_rtx_unchanging (newexp);
return newexp;
}
static void
optimize_attrs (void)
{
struct attr_desc *attr;
struct attr_value *av;
struct insn_ent *ie;
rtx newexp;
int i;
struct attr_value_list
{
struct attr_value *av;
struct insn_ent *ie;
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;
if (num_insn_ents == 0)
return;
insn_code_values = XCNEWVEC (struct attr_value_list *, insn_code_number + 2);
insn_code_values += 2;
iv = ivbuf = XNEWVEC (struct attr_value_list, num_insn_ents);
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->attr = attr;
iv->av = av;
iv->ie = ie;
iv->next = insn_code_values[ie->def->insn_code];
insn_code_values[ie->def->insn_code] = iv;
iv++;
}
gcc_assert (iv == ivbuf + num_insn_ents);
for (i = -2; i < insn_code_number; i++)
{
for (iv = insn_code_values[i]; iv; iv = iv->next)
clear_struct_flag (iv->av->value);
for (iv = insn_code_values[i]; iv; iv = iv->next)
{
struct obstack *old = rtl_obstack;
attr = iv->attr;
av = iv->av;
ie = iv->ie;
if (GET_CODE (av->value) != COND)
continue;
rtl_obstack = temp_obstack;
newexp = av->value;
while (GET_CODE (newexp) == COND)
{
rtx newexp2 = simplify_cond (newexp, ie->def->insn_code,
ie->def->insn_index);
if (newexp2 == newexp)
break;
newexp = newexp2;
}
rtl_obstack = old;
if (newexp != av->value)
{
newexp = attr_copy_rtx (newexp);
remove_insn_ent (av, ie);
av = get_attr_value (newexp, attr, ie->def->insn_code);
iv->av = av;
insert_insn_ent (av, ie);
}
}
}
free (ivbuf);
free (insn_code_values - 2);
}
static void
clear_struct_flag (rtx x)
{
int i;
int j;
enum rtx_code code;
const char *fmt;
ATTR_CURR_SIMPLIFIED_P (x) = 0;
if (ATTR_IND_SIMPLIFIED_P (x))
return;
code = GET_CODE (x);
switch (code)
{
case REG:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case EQ_ATTR:
case ATTR_FLAG:
return;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'V':
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
clear_struct_flag (XVECEXP (x, i, j));
break;
case 'e':
clear_struct_flag (XEXP (x, i));
break;
}
}
}
static void
gen_attr (rtx exp, int lineno)
{
struct attr_desc *attr;
struct attr_value *av;
const char *name_ptr;
char *p;
attr = find_attr (&XSTR (exp, 0), 1);
if (attr->default_val)
{
message_with_line (lineno, "duplicate definition for attribute %s",
attr->name);
message_with_line (attr->lineno, "previous definition");
have_error = 1;
return;
}
attr->lineno = lineno;
if (*XSTR (exp, 1) == '\0')
attr->is_numeric = 1;
else
{
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
av = oballoc (sizeof (struct attr_value));
av->value = attr_rtx (CONST_STRING, p);
av->next = attr->first_value;
attr->first_value = av;
av->first_insn = NULL;
av->num_insns = 0;
av->has_asm_insn = 0;
}
}
if (GET_CODE (XEXP (exp, 2)) == CONST)
{
attr->is_const = 1;
if (attr->is_numeric)
{
message_with_line (lineno,
"constant attributes may not take numeric values");
have_error = 1;
}
XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
}
if (! strcmp_check (attr->name, length_str) && ! attr->is_numeric)
{
message_with_line (lineno,
"`length' attribute must take numeric values");
have_error = 1;
}
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
}
static int
count_alternatives (rtx exp)
{
int i, j, n;
const char *fmt;
if (GET_CODE (exp) == MATCH_OPERAND)
return n_comma_elts (XSTR (exp, 2));
for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
switch (*fmt++)
{
case 'e':
case 'u':
n = count_alternatives (XEXP (exp, i));
if (n)
return n;
break;
case 'E':
case 'V':
if (XVEC (exp, i) != NULL)
for (j = 0; j < XVECLEN (exp, i); j++)
{
n = count_alternatives (XVECEXP (exp, i, j));
if (n)
return n;
}
}
return 0;
}
static int
compares_alternatives_p (rtx exp)
{
int i, j;
const char *fmt;
if (GET_CODE (exp) == EQ_ATTR && XSTR (exp, 0) == alternative_name)
return 1;
for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
switch (*fmt++)
{
case 'e':
case 'u':
if (compares_alternatives_p (XEXP (exp, i)))
return 1;
break;
case 'E':
for (j = 0; j < XVECLEN (exp, i); j++)
if (compares_alternatives_p (XVECEXP (exp, i, j)))
return 1;
break;
}
return 0;
}
static int
contained_in_p (rtx inner, rtx exp)
{
int i, j;
const char *fmt;
if (rtx_equal_p (inner, exp))
return 1;
for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
switch (*fmt++)
{
case 'e':
case 'u':
if (contained_in_p (inner, XEXP (exp, i)))
return 1;
break;
case 'E':
for (j = 0; j < XVECLEN (exp, i); j++)
if (contained_in_p (inner, XVECEXP (exp, i, j)))
return 1;
break;
}
return 0;
}
static void
gen_insn (rtx exp, int lineno)
{
struct insn_def *id;
id = oballoc (sizeof (struct insn_def));
id->next = defs;
defs = id;
id->def = exp;
id->lineno = lineno;
switch (GET_CODE (exp))
{
case DEFINE_INSN:
id->insn_code = insn_code_number;
id->insn_index = insn_index_number;
id->num_alternatives = count_alternatives (exp);
if (id->num_alternatives == 0)
id->num_alternatives = 1;
id->vec_idx = 4;
break;
case DEFINE_PEEPHOLE:
id->insn_code = insn_code_number;
id->insn_index = insn_index_number;
id->num_alternatives = count_alternatives (exp);
if (id->num_alternatives == 0)
id->num_alternatives = 1;
id->vec_idx = 3;
break;
case DEFINE_ASM_ATTRIBUTES:
id->insn_code = -1;
id->insn_index = -1;
id->num_alternatives = 1;
id->vec_idx = 0;
got_define_asm_attributes = 1;
break;
default:
gcc_unreachable ();
}
}
static void
gen_delay (rtx def, int lineno)
{
struct delay_desc *delay;
int i;
if (XVECLEN (def, 1) % 3 != 0)
{
message_with_line (lineno,
"number of elements in DEFINE_DELAY must be multiple of three");
have_error = 1;
return;
}
for (i = 0; i < XVECLEN (def, 1); i += 3)
{
if (XVECEXP (def, 1, i + 1))
have_annul_true = 1;
if (XVECEXP (def, 1, i + 2))
have_annul_false = 1;
}
delay = oballoc (sizeof (struct delay_desc));
delay->def = def;
delay->num = ++num_delays;
delay->next = delays;
delay->lineno = lineno;
delays = delay;
}
static void
write_test_expr (rtx exp, int flags)
{
int comparison_operator = 0;
RTX_CODE code;
struct attr_desc *attr;
printf ("(");
code = GET_CODE (exp);
switch (code)
{
case GEU: case GTU:
case LEU: case LTU:
printf ("(unsigned) ");
case EQ: case NE:
case GE: case GT:
case LE: case LT:
comparison_operator = 1;
case PLUS: case MINUS: case MULT: case DIV: case MOD:
case AND: case IOR: case XOR:
case ASHIFT: case LSHIFTRT: case ASHIFTRT:
write_test_expr (XEXP (exp, 0), flags | comparison_operator);
switch (code)
{
case EQ:
printf (" == ");
break;
case NE:
printf (" != ");
break;
case GE:
printf (" >= ");
break;
case GT:
printf (" > ");
break;
case GEU:
printf (" >= (unsigned) ");
break;
case GTU:
printf (" > (unsigned) ");
break;
case LE:
printf (" <= ");
break;
case LT:
printf (" < ");
break;
case LEU:
printf (" <= (unsigned) ");
break;
case LTU:
printf (" < (unsigned) ");
break;
case PLUS:
printf (" + ");
break;
case MINUS:
printf (" - ");
break;
case MULT:
printf (" * ");
break;
case DIV:
printf (" / ");
break;
case MOD:
printf (" %% ");
break;
case AND:
if (flags & 1)
printf (" & ");
else
printf (" && ");
break;
case IOR:
if (flags & 1)
printf (" | ");
else
printf (" || ");
break;
case XOR:
printf (" ^ ");
break;
case ASHIFT:
printf (" << ");
break;
case LSHIFTRT:
case ASHIFTRT:
printf (" >> ");
break;
default:
gcc_unreachable ();
}
write_test_expr (XEXP (exp, 1), flags | comparison_operator);
break;
case NOT:
if (! (flags & 1) && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
&& XSTR (XEXP (exp, 0), 0) == alternative_name)
{
printf ("which_alternative != %s", XSTR (XEXP (exp, 0), 1));
break;
}
case ABS: case NEG:
switch (code)
{
case NOT:
if (flags & 1)
printf ("~ ");
else
printf ("! ");
break;
case ABS:
printf ("abs ");
break;
case NEG:
printf ("-");
break;
default:
gcc_unreachable ();
}
write_test_expr (XEXP (exp, 0), flags);
break;
case EQ_ATTR_ALT:
{
int set = XINT (exp, 0), bit = 0;
if (flags & 1)
fatal ("EQ_ATTR_ALT not valid inside comparison");
if (!set)
fatal ("Empty EQ_ATTR_ALT should be optimized out");
if (!(set & (set - 1)))
{
if (!(set & 0xffff))
{
bit += 16;
set >>= 16;
}
if (!(set & 0xff))
{
bit += 8;
set >>= 8;
}
if (!(set & 0xf))
{
bit += 4;
set >>= 4;
}
if (!(set & 0x3))
{
bit += 2;
set >>= 2;
}
if (!(set & 1))
bit++;
printf ("which_alternative %s= %d",
XINT (exp, 1) ? "!" : "=", bit);
}
else
{
printf ("%s((1 << which_alternative) & 0x%x)",
XINT (exp, 1) ? "!" : "", set);
}
}
break;
case EQ_ATTR:
if (flags & 1)
fatal ("EQ_ATTR not valid inside comparison");
if (XSTR (exp, 0) == alternative_name)
{
printf ("which_alternative == %s", XSTR (exp, 1));
break;
}
attr = find_attr (&XSTR (exp, 0), 0);
gcc_assert (attr);
if (attr->is_const)
{
write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
-2, -2),
flags);
}
else
{
if (flags & 2)
printf ("attr_%s", attr->name);
else
printf ("get_attr_%s (insn)", attr->name);
printf (" == ");
write_attr_valueq (attr, XSTR (exp, 1));
}
break;
case ATTR_FLAG:
if (flags & 1)
fatal ("ATTR_FLAG not valid inside comparison");
printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
break;
case MATCH_OPERAND:
if (XSTR (exp, 1) == NULL || *XSTR (exp, 1) == '\0')
{
if (GET_MODE (exp) == VOIDmode)
fatal ("null MATCH_OPERAND specified as test");
else
printf ("GET_MODE (operands[%d]) == %smode",
XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
}
else
printf ("%s (operands[%d], %smode)",
XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
break;
case CONST_INT:
printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
break;
case SYMBOL_REF:
print_c_condition (XSTR (exp, 0));
break;
case MATCH_DUP:
printf ("INSN_ADDRESSES_SET_P () ? INSN_ADDRESSES (INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])) : 0",
XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
case PC:
printf ("insn_current_reference_address (insn)");
break;
case CONST_STRING:
printf ("%s", XSTR (exp, 0));
break;
case IF_THEN_ELSE:
write_test_expr (XEXP (exp, 0), flags & 2);
printf (" ? ");
write_test_expr (XEXP (exp, 1), flags | 1);
printf (" : ");
write_test_expr (XEXP (exp, 2), flags | 1);
break;
default:
fatal ("bad RTX code `%s' in attribute calculation\n",
GET_RTX_NAME (code));
}
printf (")");
}
static int
max_attr_value (rtx exp, int *unknownp)
{
int current_max;
int i, n;
switch (GET_CODE (exp))
{
case CONST_STRING:
current_max = atoi (XSTR (exp, 0));
break;
case COND:
current_max = max_attr_value (XEXP (exp, 1), unknownp);
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
n = max_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
if (n > current_max)
current_max = n;
}
break;
case IF_THEN_ELSE:
current_max = max_attr_value (XEXP (exp, 1), unknownp);
n = max_attr_value (XEXP (exp, 2), unknownp);
if (n > current_max)
current_max = n;
break;
default:
*unknownp = 1;
current_max = INT_MAX;
break;
}
return current_max;
}
static int
min_attr_value (rtx exp, int *unknownp)
{
int current_min;
int i, n;
switch (GET_CODE (exp))
{
case CONST_STRING:
current_min = atoi (XSTR (exp, 0));
break;
case COND:
current_min = min_attr_value (XEXP (exp, 1), unknownp);
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
n = min_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
if (n < current_min)
current_min = n;
}
break;
case IF_THEN_ELSE:
current_min = min_attr_value (XEXP (exp, 1), unknownp);
n = min_attr_value (XEXP (exp, 2), unknownp);
if (n < current_min)
current_min = n;
break;
default:
*unknownp = 1;
current_min = INT_MAX;
break;
}
return current_min;
}
static int
or_attr_value (rtx exp, int *unknownp)
{
int current_or;
int i;
switch (GET_CODE (exp))
{
case CONST_STRING:
current_or = atoi (XSTR (exp, 0));
break;
case COND:
current_or = or_attr_value (XEXP (exp, 1), unknownp);
for (i = 0; i < XVECLEN (exp, 0); i += 2)
current_or |= or_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
break;
case IF_THEN_ELSE:
current_or = or_attr_value (XEXP (exp, 1), unknownp);
current_or |= or_attr_value (XEXP (exp, 2), unknownp);
break;
default:
*unknownp = 1;
current_or = -1;
break;
}
return current_or;
}
static void
walk_attr_value (rtx exp)
{
int i, j;
const char *fmt;
RTX_CODE code;
if (exp == NULL)
return;
code = GET_CODE (exp);
switch (code)
{
case SYMBOL_REF:
if (! ATTR_IND_SIMPLIFIED_P (exp))
must_extract = must_constrain = 1;
return;
case MATCH_OPERAND:
must_extract = 1;
return;
case EQ_ATTR_ALT:
must_extract = must_constrain = 1;
break;
case EQ_ATTR:
if (XSTR (exp, 0) == alternative_name)
must_extract = must_constrain = 1;
else if (strcmp_check (XSTR (exp, 0), length_str) == 0)
length_used = 1;
return;
case MATCH_DUP:
must_extract = 1;
address_used = 1;
return;
case PC:
address_used = 1;
return;
case ATTR_FLAG:
return;
default:
break;
}
for (i = 0, fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
switch (*fmt++)
{
case 'e':
case 'u':
walk_attr_value (XEXP (exp, i));
break;
case 'E':
if (XVEC (exp, i) != NULL)
for (j = 0; j < XVECLEN (exp, i); j++)
walk_attr_value (XVECEXP (exp, i, j));
break;
}
}
static void
write_attr_get (struct attr_desc *attr)
{
struct attr_value *av, *common_av;
common_av = find_most_used (attr);
if (!attr->is_numeric)
printf ("enum attr_%s\n", attr->name);
else
printf ("int\n");
if (attr->name[0] == '*')
printf ("%s (rtx insn ATTRIBUTE_UNUSED)\n", &attr->name[1]);
else if (attr->is_const == 0)
printf ("get_attr_%s (rtx insn ATTRIBUTE_UNUSED)\n", attr->name);
else
{
printf ("get_attr_%s (void)\n", attr->name);
printf ("{\n");
for (av = attr->first_value; av; av = av->next)
if (av->num_insns == 1)
write_attr_set (attr, 2, av->value, "return", ";",
true_rtx, av->first_insn->def->insn_code,
av->first_insn->def->insn_index);
else if (av->num_insns != 0)
write_attr_set (attr, 2, av->value, "return", ";",
true_rtx, -2, 0);
printf ("}\n\n");
return;
}
printf ("{\n");
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
printf (" }\n}\n\n");
}
static rtx
eliminate_known_true (rtx known_true, rtx exp, int insn_code, int insn_index)
{
rtx term;
known_true = SIMPLIFY_TEST_EXP (known_true, insn_code, insn_index);
if (GET_CODE (known_true) == AND)
{
exp = eliminate_known_true (XEXP (known_true, 0), exp,
insn_code, insn_index);
exp = eliminate_known_true (XEXP (known_true, 1), exp,
insn_code, insn_index);
}
else
{
term = known_true;
exp = simplify_and_tree (exp, &term, insn_code, insn_index);
}
return exp;
}
static void
write_attr_set (struct attr_desc *attr, int indent, rtx value,
const char *prefix, const char *suffix, rtx known_true,
int insn_code, int insn_index)
{
if (GET_CODE (value) == COND)
{
rtx default_val = XEXP (value, 1);
rtx our_known_true = known_true;
rtx newexp;
int first_if = 1;
int i;
for (i = 0; i < XVECLEN (value, 0); i += 2)
{
rtx testexp;
rtx inner_true;
testexp = eliminate_known_true (our_known_true,
XVECEXP (value, 0, i),
insn_code, insn_index);
newexp = attr_rtx (NOT, testexp);
newexp = insert_right_side (AND, our_known_true, newexp,
insn_code, insn_index);
if (testexp == true_rtx || newexp == false_rtx)
{
default_val = XVECEXP (value, 0, i + 1);
break;
}
inner_true = insert_right_side (AND, our_known_true,
testexp, insn_code, insn_index);
if (inner_true == false_rtx)
continue;
write_indent (indent);
printf ("%sif ", first_if ? "" : "else ");
first_if = 0;
write_test_expr (testexp, 0);
printf ("\n");
write_indent (indent + 2);
printf ("{\n");
write_attr_set (attr, indent + 4,
XVECEXP (value, 0, i + 1), prefix, suffix,
inner_true, insn_code, insn_index);
write_indent (indent + 2);
printf ("}\n");
our_known_true = newexp;
}
if (! first_if)
{
write_indent (indent);
printf ("else\n");
write_indent (indent + 2);
printf ("{\n");
}
write_attr_set (attr, first_if ? indent : indent + 4, default_val,
prefix, suffix, our_known_true, insn_code, insn_index);
if (! first_if)
{
write_indent (indent + 2);
printf ("}\n");
}
}
else
{
write_indent (indent);
printf ("%s ", prefix);
write_attr_value (attr, value);
printf ("%s\n", suffix);
}
}
static void
write_insn_cases (struct insn_ent *ie, int indent)
{
for (; ie != 0; ie = ie->next)
if (ie->def->insn_code != -1)
{
write_indent (indent);
if (GET_CODE (ie->def->def) == DEFINE_PEEPHOLE)
printf ("case %d: /* define_peephole, line %d */\n",
ie->def->insn_code, ie->def->lineno);
else
printf ("case %d: /* %s */\n",
ie->def->insn_code, XSTR (ie->def->def, 0));
}
}
static void
write_attr_case (struct attr_desc *attr, struct attr_value *av,
int write_case_lines, const char *prefix, const char *suffix,
int indent, rtx known_true)
{
if (av->num_insns == 0)
return;
if (av->has_asm_insn)
{
write_indent (indent);
printf ("case -1:\n");
write_indent (indent + 2);
printf ("if (GET_CODE (PATTERN (insn)) != ASM_INPUT\n");
write_indent (indent + 2);
printf (" && asm_noperands (PATTERN (insn)) < 0)\n");
write_indent (indent + 2);
printf (" fatal_insn_not_found (insn);\n");
}
if (write_case_lines)
write_insn_cases (av->first_insn, indent);
else
{
write_indent (indent);
printf ("default:\n");
}
must_extract = must_constrain = address_used = 0;
walk_attr_value (av->value);
if (must_constrain)
{
write_indent (indent + 2);
printf ("extract_constrain_insn_cached (insn);\n");
}
else if (must_extract)
{
write_indent (indent + 2);
printf ("extract_insn_cached (insn);\n");
}
if (av->num_insns == 1)
write_attr_set (attr, indent + 2, av->value, prefix, suffix,
known_true, av->first_insn->def->insn_code,
av->first_insn->def->insn_index);
else
write_attr_set (attr, indent + 2, av->value, prefix, suffix,
known_true, -2, 0);
if (strncmp (prefix, "return", 6))
{
write_indent (indent + 2);
printf ("break;\n");
}
printf ("\n");
}
static int
write_expr_attr_cache (rtx p, struct attr_desc *attr)
{
const char *fmt;
int i, ie, j, je;
if (GET_CODE (p) == EQ_ATTR)
{
if (XSTR (p, 0) != attr->name)
return 0;
if (!attr->is_numeric)
printf (" enum attr_%s ", attr->name);
else
printf (" int ");
printf ("attr_%s = get_attr_%s (insn);\n", attr->name, attr->name);
return 1;
}
fmt = GET_RTX_FORMAT (GET_CODE (p));
ie = GET_RTX_LENGTH (GET_CODE (p));
for (i = 0; i < ie; i++)
{
switch (*fmt++)
{
case 'e':
if (write_expr_attr_cache (XEXP (p, i), attr))
return 1;
break;
case 'E':
je = XVECLEN (p, i);
for (j = 0; j < je; ++j)
if (write_expr_attr_cache (XVECEXP (p, i, j), attr))
return 1;
break;
}
}
return 0;
}
static void
write_attr_valueq (struct attr_desc *attr, const char *s)
{
if (attr->is_numeric)
{
int num = atoi (s);
printf ("%d", num);
if (num > 9 || num < 0)
printf (" /* 0x%x */", num);
}
else
{
write_upcase (attr->name);
printf ("_");
write_upcase (s);
}
}
static void
write_attr_value (struct attr_desc *attr, rtx value)
{
int op;
switch (GET_CODE (value))
{
case CONST_STRING:
write_attr_valueq (attr, XSTR (value, 0));
break;
case CONST_INT:
printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (value));
break;
case SYMBOL_REF:
print_c_condition (XSTR (value, 0));
break;
case ATTR:
{
struct attr_desc *attr2 = find_attr (&XSTR (value, 0), 0);
printf ("get_attr_%s (%s)", attr2->name,
(attr2->is_const ? "" : "insn"));
}
break;
case PLUS:
op = '+';
goto do_operator;
case MINUS:
op = '-';
goto do_operator;
case MULT:
op = '*';
goto do_operator;
case DIV:
op = '/';
goto do_operator;
case MOD:
op = '%';
goto do_operator;
do_operator:
write_attr_value (attr, XEXP (value, 0));
putchar (' ');
putchar (op);
putchar (' ');
write_attr_value (attr, XEXP (value, 1));
break;
default:
gcc_unreachable ();
}
}
static void
write_upcase (const char *str)
{
while (*str)
{
putchar (TOUPPER(*str));
str++;
}
}
static void
write_indent (int indent)
{
for (; indent > 8; indent -= 8)
printf ("\t");
for (; indent; indent--)
printf (" ");
}
static void
write_eligible_delay (const char *kind)
{
struct delay_desc *delay;
int max_slots;
char str[50];
const char *pstr;
struct attr_desc *attr;
struct attr_value *av, *common_av;
int i;
for (delay = delays, max_slots = 0; delay; delay = delay->next)
if (XVECLEN (delay->def, 1) / 3 > max_slots)
max_slots = XVECLEN (delay->def, 1) / 3;
printf ("int\n");
printf ("eligible_for_%s (rtx delay_insn ATTRIBUTE_UNUSED, int slot, rtx candidate_insn, int flags ATTRIBUTE_UNUSED)\n",
kind);
printf ("{\n");
printf (" rtx insn;\n");
printf ("\n");
printf (" gcc_assert (slot < %d);\n", max_slots);
printf ("\n");
printf (" if (!INSN_P (candidate_insn))\n");
printf (" return 0;\n");
printf ("\n");
if (num_delays > 1)
{
attr = find_attr (&delay_type_str, 0);
gcc_assert (attr);
common_av = find_most_used (attr);
printf (" insn = delay_insn;\n");
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
sprintf (str, " * %d;\n break;", max_slots);
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1, "slot +=", str, 4, true_rtx);
write_attr_case (attr, common_av, 0, "slot +=", str, 4, true_rtx);
printf (" }\n\n");
printf (" gcc_assert (slot >= %d);\n\n", max_slots);
}
if (num_delays == 1 && max_slots == 1)
{
printf (" insn = candidate_insn;\n");
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
attr = find_attr (&delay_1_0_str, 0);
gcc_assert (attr);
common_av = find_most_used (attr);
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
printf (" }\n");
}
else
{
printf (" insn = candidate_insn;\n");
printf (" switch (slot)\n");
printf (" {\n");
for (delay = delays; delay; delay = delay->next)
for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
{
printf (" case %d:\n",
(i / 3) + (num_delays == 1 ? 0 : delay->num * max_slots));
printf (" switch (recog_memoized (insn))\n");
printf ("\t{\n");
sprintf (str, "*%s_%d_%d", kind, delay->num, i / 3);
pstr = str;
attr = find_attr (&pstr, 0);
gcc_assert (attr);
common_av = find_most_used (attr);
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1, "return", ";", 8, true_rtx);
write_attr_case (attr, common_av, 0, "return", ";", 8, true_rtx);
printf (" }\n");
}
printf (" default:\n");
printf (" gcc_unreachable ();\n");
printf (" }\n");
}
printf ("}\n\n");
}
static char *
next_comma_elt (const char **pstr)
{
const char *start;
start = scan_comma_elt (pstr);
if (start == NULL)
return NULL;
return attr_string (start, *pstr - start);
}
static struct attr_desc *
find_attr (const char **name_p, int create)
{
struct attr_desc *attr;
int index;
const char *name = *name_p;
if (name == alternative_name)
return NULL;
index = name[0] & (MAX_ATTRS_INDEX - 1);
for (attr = attrs[index]; attr; attr = attr->next)
if (name == attr->name)
return attr;
for (attr = attrs[index]; attr; attr = attr->next)
if (name[0] == attr->name[0] && ! strcmp (name, attr->name))
{
*name_p = attr->name;
return attr;
}
if (! create)
return NULL;
attr = oballoc (sizeof (struct attr_desc));
attr->name = DEF_ATTR_STRING (name);
attr->first_value = attr->default_val = NULL;
attr->is_numeric = attr->is_const = attr->is_special = 0;
attr->next = attrs[index];
attrs[index] = attr;
*name_p = attr->name;
return attr;
}
static void
make_internal_attr (const char *name, rtx value, int special)
{
struct attr_desc *attr;
attr = find_attr (&name, 1);
gcc_assert (!attr->default_val);
attr->is_numeric = 1;
attr->is_const = 0;
attr->is_special = (special & ATTR_SPECIAL) != 0;
attr->default_val = get_attr_value (value, attr, -2);
}
static struct attr_value *
find_most_used (struct attr_desc *attr)
{
struct attr_value *av;
struct attr_value *most_used;
int nuses;
most_used = NULL;
nuses = -1;
for (av = attr->first_value; av; av = av->next)
if (av->num_insns > nuses)
nuses = av->num_insns, most_used = av;
return most_used;
}
static rtx
make_numeric_value (int n)
{
static rtx int_values[20];
rtx exp;
char *p;
gcc_assert (n >= 0);
if (n < 20 && int_values[n])
return int_values[n];
p = attr_printf (MAX_DIGITS, "%d", n);
exp = attr_rtx (CONST_STRING, p);
if (n < 20)
int_values[n] = exp;
return exp;
}
static rtx
copy_rtx_unchanging (rtx orig)
{
if (ATTR_IND_SIMPLIFIED_P (orig) || ATTR_CURR_SIMPLIFIED_P (orig))
return orig;
ATTR_CURR_SIMPLIFIED_P (orig) = 1;
return orig;
}
static void
write_const_num_delay_slots (void)
{
struct attr_desc *attr = find_attr (&num_delay_slots_str, 0);
struct attr_value *av;
if (attr)
{
printf ("int\nconst_num_delay_slots (rtx insn)\n");
printf ("{\n");
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
for (av = attr->first_value; av; av = av->next)
{
length_used = 0;
walk_attr_value (av->value);
if (length_used)
write_insn_cases (av->first_insn, 4);
}
printf (" default:\n");
printf (" return 1;\n");
printf (" }\n}\n\n");
}
}
struct insn_reserv
{
struct insn_reserv *next;
const char *name;
int default_latency;
rtx condexp;
int insn_num;
bool bypassed;
};
static struct insn_reserv *all_insn_reservs = 0;
static struct insn_reserv **last_insn_reserv_p = &all_insn_reservs;
static size_t n_insn_reservs;
static void
gen_insn_reserv (rtx def)
{
struct insn_reserv *decl = oballoc (sizeof (struct insn_reserv));
decl->name = DEF_ATTR_STRING (XSTR (def, 0));
decl->default_latency = XINT (def, 1);
decl->condexp = check_attr_test (XEXP (def, 2), 0, 0);
decl->insn_num = n_insn_reservs;
decl->bypassed = false;
decl->next = 0;
*last_insn_reserv_p = decl;
last_insn_reserv_p = &decl->next;
n_insn_reservs++;
}
struct bypass_list
{
struct bypass_list *next;
const char *insn;
};
static struct bypass_list *all_bypasses;
static size_t n_bypasses;
static void
gen_bypass_1 (const char *s, size_t len)
{
struct bypass_list *b;
if (len == 0)
return;
s = attr_string (s, len);
for (b = all_bypasses; b; b = b->next)
if (s == b->insn)
return;
b = oballoc (sizeof (struct bypass_list));
b->insn = s;
b->next = all_bypasses;
all_bypasses = b;
n_bypasses++;
}
static void
gen_bypass (rtx def)
{
const char *p, *base;
for (p = base = XSTR (def, 1); *p; p++)
if (*p == ',')
{
gen_bypass_1 (base, p - base);
do
p++;
while (ISSPACE (*p));
base = p;
}
gen_bypass_1 (base, p - base);
}
static void
process_bypasses (void)
{
struct bypass_list *b;
struct insn_reserv *r;
for (r = all_insn_reservs; r; r = r->next)
for (b = all_bypasses; b; b = b->next)
if (r->name == b->insn)
r->bypassed = true;
}
static void
make_automaton_attrs (void)
{
int i;
struct insn_reserv *decl;
rtx code_exp, lats_exp, byps_exp;
if (n_insn_reservs == 0)
return;
code_exp = rtx_alloc (COND);
lats_exp = rtx_alloc (COND);
XVEC (code_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
XVEC (lats_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
XEXP (code_exp, 1) = make_numeric_value (n_insn_reservs + 1);
XEXP (lats_exp, 1) = make_numeric_value (0);
for (decl = all_insn_reservs, i = 0;
decl;
decl = decl->next, i += 2)
{
XVECEXP (code_exp, 0, i) = decl->condexp;
XVECEXP (lats_exp, 0, i) = decl->condexp;
XVECEXP (code_exp, 0, i+1) = make_numeric_value (decl->insn_num);
XVECEXP (lats_exp, 0, i+1) = make_numeric_value (decl->default_latency);
}
if (n_bypasses == 0)
byps_exp = make_numeric_value (0);
else
{
process_bypasses ();
byps_exp = rtx_alloc (COND);
XVEC (byps_exp, 0) = rtvec_alloc (n_bypasses * 2);
XEXP (byps_exp, 1) = make_numeric_value (0);
for (decl = all_insn_reservs, i = 0;
decl;
decl = decl->next)
if (decl->bypassed)
{
XVECEXP (byps_exp, 0, i) = decl->condexp;
XVECEXP (byps_exp, 0, i+1) = make_numeric_value (1);
i += 2;
}
}
make_internal_attr ("*internal_dfa_insn_code", code_exp, ATTR_NONE);
make_internal_attr ("*insn_default_latency", lats_exp, ATTR_NONE);
make_internal_attr ("*bypass_p", byps_exp, ATTR_NONE);
}
int
main (int argc, char **argv)
{
rtx desc;
struct attr_desc *attr;
struct insn_def *id;
rtx tem;
int i;
progname = "genattrtab";
if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
return (FATAL_EXIT_CODE);
obstack_init (hash_obstack);
obstack_init (temp_obstack);
true_rtx = rtx_alloc (CONST_INT);
XWINT (true_rtx, 0) = 1;
false_rtx = rtx_alloc (CONST_INT);
XWINT (false_rtx, 0) = 0;
ATTR_IND_SIMPLIFIED_P (true_rtx) = ATTR_IND_SIMPLIFIED_P (false_rtx) = 1;
ATTR_PERMANENT_P (true_rtx) = ATTR_PERMANENT_P (false_rtx) = 1;
alternative_name = DEF_ATTR_STRING ("alternative");
length_str = DEF_ATTR_STRING ("length");
delay_type_str = DEF_ATTR_STRING ("*delay_type");
delay_1_0_str = DEF_ATTR_STRING ("*delay_1_0");
num_delay_slots_str = DEF_ATTR_STRING ("*num_delay_slots");
printf ("/* Generated automatically by the program `genattrtab'\n\
from the machine description file `md'. */\n\n");
while (1)
{
int lineno;
desc = read_md_rtx (&lineno, &insn_code_number);
if (desc == NULL)
break;
switch (GET_CODE (desc))
{
case DEFINE_INSN:
case DEFINE_PEEPHOLE:
case DEFINE_ASM_ATTRIBUTES:
gen_insn (desc, lineno);
break;
case DEFINE_ATTR:
gen_attr (desc, lineno);
break;
case DEFINE_DELAY:
gen_delay (desc, lineno);
break;
case DEFINE_INSN_RESERVATION:
gen_insn_reserv (desc);
break;
case DEFINE_BYPASS:
gen_bypass (desc);
break;
default:
break;
}
if (GET_CODE (desc) != DEFINE_ASM_ATTRIBUTES)
insn_index_number++;
}
if (have_error)
return FATAL_EXIT_CODE;
insn_code_number++;
if (! got_define_asm_attributes)
{
tem = rtx_alloc (DEFINE_ASM_ATTRIBUTES);
XVEC (tem, 0) = rtvec_alloc (0);
gen_insn (tem, 0);
}
if (num_delays)
expand_delays ();
printf ("#include \"config.h\"\n");
printf ("#include \"system.h\"\n");
printf ("#include \"coretypes.h\"\n");
printf ("#include \"tm.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"tm_p.h\"\n");
printf ("#include \"insn-config.h\"\n");
printf ("#include \"recog.h\"\n");
printf ("#include \"regs.h\"\n");
printf ("#include \"real.h\"\n");
printf ("#include \"output.h\"\n");
printf ("#include \"insn-attr.h\"\n");
printf ("#include \"toplev.h\"\n");
printf ("#include \"flags.h\"\n");
printf ("#include \"function.h\"\n");
printf ("\n");
printf ("#define operands recog_data.operand\n\n");
insn_alternatives = oballoc (insn_code_number * sizeof (int));
for (id = defs; id; id = id->next)
if (id->insn_code >= 0)
insn_alternatives[id->insn_code] = (1 << id->num_alternatives) - 1;
insn_n_alternatives = oballoc (insn_code_number * sizeof (int));
for (id = defs; id; id = id->next)
if (id->insn_code >= 0)
insn_n_alternatives[id->insn_code] = id->num_alternatives;
make_automaton_attrs ();
check_defs ();
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
attr->default_val->value
= check_attr_value (attr->default_val->value, attr);
if (have_error)
return FATAL_EXIT_CODE;
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
fill_attr (attr);
make_length_attrs ();
optimize_attrs ();
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
{
if (! attr->is_special && ! attr->is_const)
write_attr_get (attr);
}
if (num_delays)
{
write_eligible_delay ("delay");
if (have_annul_true)
write_eligible_delay ("annul_true");
if (have_annul_false)
write_eligible_delay ("annul_false");
}
write_const_num_delay_slots ();
write_length_unit_log ();
fflush (stdout);
return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
}