#include "hconfig.h"
#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#include "obstack.h"
static struct obstack obstack, obstack1, obstack2;
struct obstack *rtl_obstack = &obstack;
struct obstack *hash_obstack = &obstack1;
struct obstack *temp_obstack = &obstack2;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
char **insn_name_ptr = 0;
void fatal PVPROTO ((const char *, ...))
ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
#define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
struct insn_def
{
int insn_code;
int insn_index;
struct insn_def *next;
rtx def;
int num_alternatives;
int vec_idx;
};
struct insn_ent
{
int insn_code;
int insn_index;
struct insn_ent *next;
};
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;
unsigned is_numeric : 1;
unsigned negative_ok : 1;
unsigned unsigned_p : 1;
unsigned is_const : 1;
unsigned is_special : 1;
unsigned func_units_p : 1;
unsigned blockage_p : 1;
struct attr_value *first_value;
struct attr_value *default_val;
};
#define NULL_ATTR (struct attr_desc *) NULL
struct range
{
int min;
int max;
};
struct delay_desc
{
rtx def;
struct delay_desc *next;
int num;
};
struct function_unit_op
{
rtx condexp;
struct function_unit_op *next;
int num;
int ready;
int issue_delay;
rtx conflict_exp;
rtx issue_exp;
};
struct function_unit
{
char *name;
struct function_unit *next;
int num;
int multiplicity;
int simultaneity;
rtx condexp;
int num_opclasses;
struct function_unit_op *ops;
int needs_conflict_function;
int needs_blockage_function;
int needs_range_function;
rtx default_cost;
struct range issue_delay;
int max_blockage;
};
#define MAX_ATTRS_INDEX 256
static struct attr_desc *attrs[MAX_ATTRS_INDEX];
static struct insn_def *defs;
static struct delay_desc *delays;
static struct function_unit *units;
struct dimension
{
struct attr_desc *attr;
rtx values;
rtx current_value;
int num_values;
};
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_units, num_unit_opclasses;
static int num_insn_ents;
enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, ORX_OP, MAX_OP, MIN_OP, RANGE_OP};
static int *insn_n_alternatives;
static int *insn_alternatives;
static char *current_alternative_string;
static rtx true_rtx, false_rtx;
static char *alternative_name;
int reload_completed = 0;
int optimize = 0;
#define SIMPLIFY_TEST_EXP(EXP,INSN_CODE,INSN_INDEX) \
(RTX_UNCHANGING_P (EXP) || MEM_IN_STRUCT_P (EXP) ? (EXP) \
: simplify_test_exp (EXP, INSN_CODE, INSN_INDEX))
#define SIMPLIFY_ALTERNATIVE(EXP) \
if (current_alternative_string \
&& GET_CODE ((EXP)) == EQ_ATTR \
&& XSTR ((EXP), 0) == alternative_name) \
(EXP) = (XSTR ((EXP), 1) == current_alternative_string \
? true_rtx : false_rtx);
struct _global_rtl global_rtl;
rtx pic_offset_table_rtx;
static void attr_hash_add_rtx PROTO((int, rtx));
static void attr_hash_add_string PROTO((int, char *));
static rtx attr_rtx PVPROTO((enum rtx_code, ...));
static char *attr_printf PVPROTO((int, const char *, ...))
ATTRIBUTE_PRINTF_2;
static char *attr_string PROTO((const char *, int));
static rtx check_attr_test PROTO((rtx, int));
static rtx check_attr_value PROTO((rtx, struct attr_desc *));
static rtx convert_set_attr_alternative PROTO((rtx, int, int));
static rtx convert_set_attr PROTO((rtx, int, int));
static void check_defs PROTO((void));
#if 0
static rtx convert_const_symbol_ref PROTO((rtx, struct attr_desc *));
#endif
static rtx make_canonical PROTO((struct attr_desc *, rtx));
static struct attr_value *get_attr_value PROTO((rtx, struct attr_desc *, int));
static rtx copy_rtx_unchanging PROTO((rtx));
static rtx copy_boolean PROTO((rtx));
static void expand_delays PROTO((void));
static rtx operate_exp PROTO((enum operator, rtx, rtx));
static void expand_units PROTO((void));
static rtx simplify_knowing PROTO((rtx, rtx));
static rtx encode_units_mask PROTO((rtx));
static void fill_attr PROTO((struct attr_desc *));
static rtx substitute_address PROTO((rtx, rtx (*) (), rtx (*) ()));
static void make_length_attrs PROTO((void));
static rtx identity_fn PROTO((rtx));
static rtx zero_fn PROTO((rtx));
static rtx one_fn PROTO((rtx));
static rtx max_fn PROTO((rtx));
static void write_length_unit_log PROTO ((void));
static rtx simplify_cond PROTO((rtx, int, int));
#if 0
static rtx simplify_by_alternatives PROTO((rtx, int, int));
#endif
static rtx simplify_by_exploding PROTO((rtx));
static int find_and_mark_used_attributes PROTO((rtx, rtx *, int *));
static void unmark_used_attributes PROTO((rtx, struct dimension *, int));
static int add_values_to_cover PROTO((struct dimension *));
static int increment_current_value PROTO((struct dimension *, int));
static rtx test_for_current_value PROTO((struct dimension *, int));
static rtx simplify_with_current_value PROTO((rtx, struct dimension *, int));
static rtx simplify_with_current_value_aux PROTO((rtx));
static void clear_struct_flag PROTO((rtx));
static int count_sub_rtxs PROTO((rtx, int));
static void remove_insn_ent PROTO((struct attr_value *, struct insn_ent *));
static void insert_insn_ent PROTO((struct attr_value *, struct insn_ent *));
static rtx insert_right_side PROTO((enum rtx_code, rtx, rtx, int, int));
static rtx make_alternative_compare PROTO((int));
static int compute_alternative_mask PROTO((rtx, enum rtx_code));
static rtx evaluate_eq_attr PROTO((rtx, rtx, int, int));
static rtx simplify_and_tree PROTO((rtx, rtx *, int, int));
static rtx simplify_or_tree PROTO((rtx, rtx *, int, int));
static rtx simplify_test_exp PROTO((rtx, int, int));
static void optimize_attrs PROTO((void));
static void gen_attr PROTO((rtx));
static int count_alternatives PROTO((rtx));
static int compares_alternatives_p PROTO((rtx));
static int contained_in_p PROTO((rtx, rtx));
static void gen_insn PROTO((rtx));
static void gen_delay PROTO((rtx));
static void gen_unit PROTO((rtx));
static void write_test_expr PROTO((rtx, int));
static int max_attr_value PROTO((rtx, int*));
static int or_attr_value PROTO((rtx, int*));
static void walk_attr_value PROTO((rtx));
static void write_attr_get PROTO((struct attr_desc *));
static rtx eliminate_known_true PROTO((rtx, rtx, int, int));
static void write_attr_set PROTO((struct attr_desc *, int, rtx,
const char *, const char *, rtx,
int, int));
static void write_attr_case PROTO((struct attr_desc *, struct attr_value *,
int, const char *, const char *, int, rtx));
static void write_unit_name PROTO((const char *, int, const char *));
static void write_attr_valueq PROTO((struct attr_desc *, char *));
static void write_attr_value PROTO((struct attr_desc *, rtx));
static void write_upcase PROTO((char *));
static void write_indent PROTO((int));
static void write_eligible_delay PROTO((const char *));
static void write_function_unit_info PROTO((void));
static void write_complex_function PROTO((struct function_unit *, const char *,
const char *));
static int write_expr_attr_cache PROTO((rtx, struct attr_desc *));
static void write_toplevel_expr PROTO((rtx));
static int n_comma_elts PROTO((char *));
static char *next_comma_elt PROTO((char **));
static struct attr_desc *find_attr PROTO((const char *, int));
static void make_internal_attr PROTO((const char *, rtx, int));
static struct attr_value *find_most_used PROTO((struct attr_desc *));
static rtx find_single_value PROTO((struct attr_desc *));
static rtx make_numeric_value PROTO((int));
static void extend_range PROTO((struct range *, int, int));
#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
struct attr_hash *attr_hash_table[RTL_HASH_SIZE];
#define RTL_HASH(RTL) ((long) (RTL) & 0777777)
static void
attr_hash_add_rtx (hashcode, rtl)
int hashcode;
rtx rtl;
{
register struct attr_hash *h;
h = (struct attr_hash *) 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 (hashcode, str)
int hashcode;
char *str;
{
register struct attr_hash *h;
h = (struct attr_hash *) 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 VPROTO((enum rtx_code code, ...))
{
#ifndef ANSI_PROTOTYPES
enum rtx_code code;
#endif
va_list p;
register int i;
register char *fmt;
register rtx rt_val;
int hashcode;
register struct attr_hash *h;
struct obstack *old_obstack = rtl_obstack;
VA_START (p, code);
#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum rtx_code);
#endif
if (GET_RTX_CLASS (code) == '1')
{
rtx arg0 = va_arg (p, rtx);
if (! RTX_INTEGRATED_P (arg0))
{
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
va_end (p);
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)
goto found;
if (h == 0)
{
rtl_obstack = hash_obstack;
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);
if (! RTX_INTEGRATED_P (arg0) || ! RTX_INTEGRATED_P (arg1))
{
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
XEXP (rt_val, 1) = arg1;
va_end (p);
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)
goto found;
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 *);
if (code == SYMBOL_REF)
arg0 = attr_string (arg0, strlen (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)
goto found;
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)
goto found;
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;
if (arg0 == 1)
return true_rtx;
goto nohash;
}
else
{
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:
abort();
}
}
va_end (p);
return rt_val;
}
rtl_obstack = old_obstack;
va_end (p);
attr_hash_add_rtx (hashcode, rt_val);
RTX_INTEGRATED_P (rt_val) = 1;
return rt_val;
found:
va_end (p);
return h->u.rtl;
}
static char *
attr_printf VPROTO((register int len, const char *fmt, ...))
{
#ifndef ANSI_PROTOTYPES
register int len;
const char *fmt;
#endif
va_list p;
register char *str;
VA_START (p, fmt);
#ifndef ANSI_PROTOTYPES
len = va_arg (p, int);
fmt = va_arg (p, const char *);
#endif
str = (char *) alloca (len);
vsprintf (str, fmt, p);
va_end (p);
return attr_string (str, strlen (str));
}
rtx
attr_eq (name, value)
char *name, *value;
{
return attr_rtx (EQ_ATTR, attr_string (name, strlen (name)),
attr_string (value, strlen (value)));
}
char *
attr_numeral (n)
int n;
{
return XSTR (make_numeric_value (n), 0);
}
static char *
attr_string (str, len)
const char *str;
int len;
{
register struct attr_hash *h;
int hashcode;
int i;
register 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 = (char *) obstack_alloc (hash_obstack, len + 1);
bcopy (str, new_str, len);
new_str[len] = '\0';
attr_hash_add_string (hashcode, new_str);
return new_str;
}
int
attr_equal_p (x, y)
rtx x, y;
{
return (x == y || (! (RTX_INTEGRATED_P (x) && RTX_INTEGRATED_P (y))
&& rtx_equal_p (x, y)));
}
rtx
attr_copy_rtx (orig)
register rtx orig;
{
register rtx copy;
register int i, j;
register RTX_CODE code;
register char *format_ptr;
if (RTX_INTEGRATED_P (orig))
return orig;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
return orig;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
copy->in_struct = orig->in_struct;
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
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:
abort ();
}
}
return copy;
}
static rtx
check_attr_test (exp, is_const)
rtx exp;
int is_const;
{
struct attr_desc *attr;
struct attr_value *av;
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);
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"))
{
XSTR (exp, 0) = alternative_name;
RTX_UNCHANGING_P (exp) = 1;
return exp;
}
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)
RTX_UNCHANGING_P (exp) = 1;
if (attr->is_numeric)
{
for (p = XSTR (exp, 1); *p; p++)
if (*p < '0' || *p > '9')
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
{
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);
}
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);
XEXP (exp, 1) = check_attr_test (XEXP (exp, 1), is_const);
break;
case NOT:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const);
break;
case MATCH_INSN:
case MATCH_OPERAND:
if (is_const)
fatal ("RTL operator \"%s\" not valid in constant attribute test",
GET_RTX_NAME (GET_CODE (exp)));
RTX_UNCHANGING_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)));
RTX_UNCHANGING_P (exp) = 1;
break;
case SYMBOL_REF:
if (is_const)
{
exp = attr_rtx (SYMBOL_REF, XSTR (exp, 0));
RTX_UNCHANGING_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 (exp, attr)
rtx exp;
struct attr_desc *attr;
{
struct attr_value *av;
char *p;
int i;
switch (GET_CODE (exp))
{
case CONST_INT:
if (attr && ! attr->is_numeric)
fatal ("CONST_INT not valid for non-numeric `%s' attribute",
attr->name);
if (INTVAL (exp) < 0 && ! attr->negative_ok)
fatal ("Negative numeric value specified for `%s' attribute",
attr->name);
break;
case CONST_STRING:
if (! strcmp (XSTR (exp, 0), "*"))
break;
if (attr == 0 || attr->is_numeric)
{
p = XSTR (exp, 0);
if (attr && attr->negative_ok && *p == '-')
p++;
for (; *p; p++)
if (*p > '9' || *p < '0')
fatal ("Non-numeric value for numeric `%s' attribute",
attr ? attr->name : "internal");
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)
fatal ("Unknown value `%s' for `%s' attribute",
XSTR (exp, 0), attr ? attr->name : "internal");
break;
case IF_THEN_ELSE:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0),
attr ? attr->is_const : 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)
fatal ("Invalid operation `%s' for non-numeric attribute value",
GET_RTX_NAME (GET_CODE (exp)));
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:
XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
break;
case COND:
if (XVECLEN (exp, 0) % 2 != 0)
fatal ("First operand of COND must have even length");
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);
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)
fatal ("Unknown attribute `%s' in ATTR", XSTR (exp, 0));
else if ((attr && attr->is_const) && ! attr2->is_const)
fatal ("Non-constant attribute `%s' referenced from `%s'",
XSTR (exp, 0), attr->name);
else if (attr
&& (attr->is_numeric != attr2->is_numeric
|| (! attr->negative_ok && attr2->negative_ok)))
fatal ("Numeric attribute mismatch calling `%s' from `%s'",
XSTR (exp, 0), attr->name);
}
break;
case SYMBOL_REF:
return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
default:
fatal ("Invalid operation `%s' for attribute value",
GET_RTX_NAME (GET_CODE (exp)));
}
return exp;
}
static rtx
convert_set_attr_alternative (exp, num_alt, insn_index)
rtx exp;
int num_alt;
int insn_index;
{
rtx condexp;
int i;
if (XVECLEN (exp, 1) != num_alt)
fatal ("Bad number of entries in SET_ATTR_ALTERNATIVE for insn %d",
insn_index);
condexp = rtx_alloc (COND);
XVEC (condexp, 0) = rtvec_alloc ((num_alt - 1) * 2);
for (i = 0; i < num_alt - 1; i++)
{
char *p;
p = attr_numeral (i);
XVECEXP (condexp, 0, 2 * i) = attr_eq (alternative_name, p);
#if 0
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) = p;
#endif
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 (exp, num_alt, insn_index)
rtx exp;
int num_alt;
int insn_index;
{
rtx newexp;
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, num_alt, insn_index);
}
static void
check_defs ()
{
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)
fatal ("Bad attribute set in pattern %d", id->insn_index);
break;
case SET_ATTR_ALTERNATIVE:
value = convert_set_attr_alternative (value,
id->num_alternatives,
id->insn_index);
break;
case SET_ATTR:
value = convert_set_attr (value, id->num_alternatives,
id->insn_index);
break;
default:
fatal ("Invalid attribute code `%s' for pattern %d",
GET_RTX_NAME (GET_CODE (value)), id->insn_index);
}
if ((attr = find_attr (XSTR (XEXP (value, 0), 0), 0)) == NULL)
fatal ("Unknown attribute `%s' for pattern number %d",
XSTR (XEXP (value, 0), 0), id->insn_index);
XVECEXP (id->def, id->vec_idx, i) = value;
XEXP (value, 1) = check_attr_value (XEXP (value, 1), attr);
}
}
}
#if 0
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++;
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, *string;
rtx value;
string = p = (char *) oballoc (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';
value = attr_rtx (SYMBOL_REF, string);
RTX_UNCHANGING_P (value) = 1;
XVECEXP (condexp, 0, 2 * i) = attr_rtx (EQ, exp, value);
XVECEXP (condexp, 0, 2 * i + 1) = av->value;
}
return condexp;
}
#endif
static rtx
make_canonical (attr, exp)
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;
}
break;
case SYMBOL_REF:
if (!attr->is_const || RTX_UNCHANGING_P (exp))
break;
RTX_UNCHANGING_P (exp) = 1;
#if 0
exp = convert_const_symbol_ref (exp, attr);
RTX_UNCHANGING_P (exp) = 1;
exp = check_attr_value (exp, attr);
goto cond;
#else
exp = check_attr_value (exp, attr);
break;
#endif
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 (exp)
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)));
return exp;
}
static struct attr_value *
get_attr_value (value, attr, insn_code)
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->insn_code]))
return av;
av = (struct attr_value *) 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 ()
{
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", condexp, 0);
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", condexp, 1);
}
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, 1);
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, 1);
}
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, 1);
}
}
}
}
static rtx
operate_exp (op, left, right)
enum operator op;
rtx left, right;
{
int left_value, right_value;
rtx newexp;
int i;
if (GET_CODE (left) == CONST_STRING)
{
if (GET_CODE (right) == CONST_STRING)
{
left_value = atoi (XSTR (left, 0));
right_value = atoi (XSTR (right, 0));
switch (op)
{
case PLUS_OP:
i = left_value + right_value;
break;
case MINUS_OP:
i = left_value - right_value;
break;
case POS_MINUS_OP:
if (left_value > right_value)
i = left_value - right_value;
else
i = 0;
break;
case OR_OP:
case ORX_OP:
i = left_value | right_value;
break;
case EQ_OP:
i = left_value == right_value;
break;
case RANGE_OP:
i = (left_value << (HOST_BITS_PER_INT / 2)) | right_value;
break;
case MAX_OP:
if (left_value > right_value)
i = left_value;
else
i = right_value;
break;
case MIN_OP:
if (left_value < right_value)
i = left_value;
else
i = right_value;
break;
default:
abort ();
}
if (i == left_value)
return left;
if (i == right_value)
return right;
return make_numeric_value (i);
}
else if (GET_CODE (right) == IF_THEN_ELSE)
{
rtx newleft = operate_exp (op, left, XEXP (right, 1));
rtx newright = operate_exp (op, left, XEXP (right, 2));
if (rtx_equal_p (newleft, newright))
return newleft;
return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright);
}
else if (GET_CODE (right) == COND)
{
int allsame = 1;
rtx defval;
newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0));
defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1));
for (i = 0; i < XVECLEN (right, 0); i += 2)
{
XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i);
XVECEXP (newexp, 0, i + 1)
= operate_exp (op, left, XVECEXP (right, 0, i + 1));
if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),
defval))
allsame = 0;
}
if (allsame)
{
obstack_free (rtl_obstack, newexp);
return operate_exp (op, left, XEXP (right, 1));
}
if (rtx_equal_p (newexp, right))
{
obstack_free (rtl_obstack, newexp);
return right;
}
return newexp;
}
else
fatal ("Badly formed attribute value");
}
else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE)
{
return attr_rtx (IOR, left, right);
}
else if (GET_CODE (left) == IF_THEN_ELSE)
{
rtx newleft = operate_exp (op, XEXP (left, 1), right);
rtx newright = operate_exp (op, XEXP (left, 2), right);
if (rtx_equal_p (newleft, newright))
return newleft;
return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright);
}
else if (GET_CODE (left) == COND)
{
int allsame = 1;
rtx defval;
newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0));
defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right);
for (i = 0; i < XVECLEN (left, 0); i += 2)
{
XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i);
XVECEXP (newexp, 0, i + 1)
= operate_exp (op, XVECEXP (left, 0, i + 1), right);
if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1),
defval))
allsame = 0;
}
if (allsame)
{
obstack_free (rtl_obstack, newexp);
return operate_exp (op, XEXP (left, 1), right);
}
if (rtx_equal_p (newexp, left))
{
obstack_free (rtl_obstack, newexp);
return left;
}
return newexp;
}
else
fatal ("Badly formed attribute value.");
return NULL;
}
static void
expand_units ()
{
struct function_unit *unit, **unit_num;
struct function_unit_op *op, **op_array, ***unit_ops;
rtx unitsmask;
rtx readycost;
rtx newexp;
const char *str;
int i, j, u, num, nvalues;
for (unit = units; unit; unit = unit->next)
{
unit->condexp = check_attr_test (unit->condexp, 0);
for (op = unit->ops; op; op = op->next)
{
rtx issue_delay = make_numeric_value (op->issue_delay);
rtx issue_exp = issue_delay;
if (op->conflict_exp != true_rtx)
issue_exp = attr_rtx (IF_THEN_ELSE, op->conflict_exp,
issue_exp, make_numeric_value (0));
issue_exp = check_attr_value (make_canonical (NULL_ATTR,
issue_exp),
NULL_ATTR);
issue_exp = simplify_knowing (issue_exp, unit->condexp);
op->issue_exp = issue_exp;
unit->needs_conflict_function = (unit->issue_delay.min
!= unit->issue_delay.max);
if (unit->needs_conflict_function)
{
str = attr_printf (strlen (unit->name) + sizeof ("*_cost_") + MAX_DIGITS,
"*%s_cost_%d", unit->name, op->num);
make_internal_attr (str, issue_exp, 1);
}
op->condexp = check_attr_test (op->condexp, 0);
}
}
unitsmask = make_numeric_value (0);
newexp = rtx_alloc (IF_THEN_ELSE);
XEXP (newexp, 2) = make_numeric_value (0);
#define NUM_UNITOP_CUTOFF 20
if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
{
for (unit = units; unit; unit = unit->next)
{
XEXP (newexp, 0) = unit->condexp;
XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
unitsmask = operate_exp (OR_OP, unitsmask, newexp);
}
}
else
{
for (unit = units; unit; unit = unit->next)
{
XEXP (newexp, 0) = unit->condexp;
XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp));
}
}
unitsmask = simplify_by_exploding (unitsmask);
if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
unitsmask = encode_units_mask (unitsmask);
else
{
unitsmask = attr_rtx (FFS, unitsmask);
}
make_internal_attr ("*function_units_used", unitsmask, 10);
unit_ops = (struct function_unit_op ***)
alloca ((num_units + 1) * sizeof (struct function_unit_op **));
unit_num = (struct function_unit **)
alloca ((num_units + 1) * sizeof (struct function_unit *));
unit_num[num_units] = unit = (struct function_unit *)
alloca (sizeof (struct function_unit));
unit->num = num_units;
unit->num_opclasses = 0;
for (unit = units; unit; unit = unit->next)
{
unit_num[num_units]->num_opclasses += unit->num_opclasses;
unit_num[unit->num] = unit;
unit_ops[unit->num] = op_array = (struct function_unit_op **)
alloca (unit->num_opclasses * sizeof (struct function_unit_op *));
for (op = unit->ops; op; op = op->next)
op_array[op->num] = op;
}
unit_ops[num_units] = op_array = (struct function_unit_op **)
alloca (unit_num[num_units]->num_opclasses
* sizeof (struct function_unit_op *));
for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next)
bcopy ((char *) unit_ops[unit->num], (char *) &op_array[i],
unit->num_opclasses * sizeof (struct function_unit_op *));
for (u = 0; u <= num_units; u++)
{
rtx orexp;
int value;
unit = unit_num[u];
op_array = unit_ops[unit->num];
num = unit->num_opclasses;
for (i = 0; i < num; i++)
for (j = num - 1; j > i; j--)
if (op_array[j-1]->ready < op_array[j]->ready)
{
op = op_array[j];
op_array[j] = op_array[j-1];
op_array[j-1] = op;
}
nvalues = 0; value = 1;
for (i = num - 1; i >= 0; i--)
if (op_array[i]->ready > value)
{
value = op_array[i]->ready;
nvalues++;
}
if (nvalues == 0)
readycost = make_numeric_value (1);
else
{
readycost = rtx_alloc (COND);
XVEC (readycost, 0) = rtvec_alloc (nvalues * 2);
XEXP (readycost, 1) = make_numeric_value (1);
nvalues = 0; orexp = false_rtx; value = op_array[0]->ready;
for (i = 0; i < num; i++)
{
op = op_array[i];
if (op->ready <= 1)
break;
else if (op->ready == value)
orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2);
else
{
XVECEXP (readycost, 0, nvalues * 2) = orexp;
XVECEXP (readycost, 0, nvalues * 2 + 1)
= make_numeric_value (value);
nvalues++;
value = op->ready;
orexp = op->condexp;
}
}
XVECEXP (readycost, 0, nvalues * 2) = orexp;
XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value);
}
if (u < num_units)
{
rtx max_blockage = 0, min_blockage = 0;
readycost = simplify_knowing (readycost, unit->condexp);
for (op = unit->ops; op; op = op->next)
{
#ifdef HAIFA
rtx blockage = op->issue_exp;
#else
rtx blockage = operate_exp (POS_MINUS_OP, readycost,
make_numeric_value (1));
if (unit->simultaneity != 0)
{
rtx filltime = make_numeric_value ((unit->simultaneity - 1)
* unit->issue_delay.min);
blockage = operate_exp (MIN_OP, blockage, filltime);
}
blockage = operate_exp (POS_MINUS_OP,
make_numeric_value (op->ready),
blockage);
blockage = operate_exp (MAX_OP, blockage, op->issue_exp);
#endif
blockage = simplify_knowing (blockage, unit->condexp);
if (max_blockage == 0)
max_blockage = min_blockage = blockage;
else
{
max_blockage
= simplify_knowing (operate_exp (MAX_OP, max_blockage,
blockage),
unit->condexp);
min_blockage
= simplify_knowing (operate_exp (MIN_OP, min_blockage,
blockage),
unit->condexp);
}
str = attr_printf (strlen (unit->name) + sizeof ("*_block_") + MAX_DIGITS,
"*%s_block_%d", unit->name, op->num);
make_internal_attr (str, blockage, 1);
}
{
int unknown;
unit->max_blockage = max_attr_value (max_blockage, &unknown);
}
newexp = operate_exp (EQ_OP, max_blockage, min_blockage);
newexp = simplify_knowing (newexp, unit->condexp);
unit->needs_blockage_function
= (GET_CODE (newexp) != CONST_STRING
|| atoi (XSTR (newexp, 0)) != 1);
unit->needs_range_function
= (unit->needs_blockage_function
|| GET_CODE (max_blockage) != CONST_STRING);
if (unit->needs_range_function)
{
newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);
newexp = simplify_knowing (newexp, unit->condexp);
str = attr_printf (strlen (unit->name) + sizeof ("*_unit_blockage_range"),
"*%s_unit_blockage_range", unit->name);
make_internal_attr (str, newexp, 20);
}
str = attr_printf (strlen (unit->name) + sizeof ("*_unit_ready_cost"),
"*%s_unit_ready_cost", unit->name);
}
else
str = "*result_ready_cost";
make_internal_attr (str, readycost, 0);
}
for (unit = units; unit; unit = unit->next)
{
rtx caseexp;
if (! unit->needs_conflict_function
&& ! unit->needs_blockage_function)
continue;
caseexp = rtx_alloc (COND);
XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2);
for (op = unit->ops; op; op = op->next)
{
if (op->num == unit->num_opclasses - 1)
{
XEXP (caseexp, 1) = make_numeric_value (op->num);
}
else
{
XVECEXP (caseexp, 0, op->num * 2) = op->condexp;
XVECEXP (caseexp, 0, op->num * 2 + 1)
= make_numeric_value (op->num);
}
}
str = attr_printf (strlen (unit->name) + sizeof ("*_cases"),
"*%s_cases", unit->name);
make_internal_attr (str, caseexp, 1);
}
}
static rtx
simplify_knowing (exp, known_true)
rtx exp, known_true;
{
if (GET_CODE (exp) != CONST_STRING)
{
int unknown = 0, max;
max = max_attr_value (exp, &unknown);
if (! unknown)
{
exp = attr_rtx (IF_THEN_ELSE, known_true, exp,
make_numeric_value (max));
exp = simplify_by_exploding (exp);
}
}
return exp;
}
static rtx
encode_units_mask (x)
rtx x;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
code = GET_CODE (x);
switch (code)
{
case CONST_STRING:
i = atoi (XSTR (x, 0));
if (i < 0)
abort ();
else if (i != 0 && i == (i & -i))
for (j = 0; (i >>= 1) != 0; j++)
;
else
j = ~i;
return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j));
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case EQ_ATTR:
return x;
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++)
XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j));
break;
case 'e':
XEXP (x, i) = encode_units_mask (XEXP (x, i));
break;
}
}
return x;
}
static void
fill_attr (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 (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 = (struct insn_ent *) oballoc (sizeof (struct insn_ent));
ie->insn_code = id->insn_code;
ie->insn_index = id->insn_code;
insert_insn_ent (av, ie);
}
}
static rtx
substitute_address (exp, no_address_fn, address_fn)
rtx exp;
rtx (*no_address_fn) ();
rtx (*address_fn) ();
{
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 ()
{
static const char *new_names[] = {"*insn_default_length",
"*insn_variable_length_p",
"*insn_current_length"};
static rtx (*no_address_fn[]) PROTO((rtx)) = {identity_fn, zero_fn, zero_fn};
static rtx (*address_fn[]) PROTO((rtx)) = {max_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", 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 < sizeof new_names / sizeof new_names[0]; i++)
{
make_internal_attr (new_names[i],
substitute_address (length_attr->default_val->value,
no_address_fn[i], address_fn[i]),
0);
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->insn_code);
new_ie = (struct insn_ent *) oballoc (sizeof (struct insn_ent));
new_ie->insn_code = ie->insn_code;
new_ie->insn_index = ie->insn_index;
insert_insn_ent (new_av, new_ie);
}
}
}
static rtx
identity_fn (exp)
rtx exp;
{
return exp;
}
static rtx
zero_fn (exp)
rtx exp ATTRIBUTE_UNUSED;
{
return make_numeric_value (0);
}
static rtx
one_fn (exp)
rtx exp ATTRIBUTE_UNUSED;
{
return make_numeric_value (1);
}
static rtx
max_fn (exp)
rtx exp;
{
int unknown;
return make_numeric_value (max_attr_value (exp, &unknown));
}
static void
write_length_unit_log ()
{
struct attr_desc *length_attr = find_attr ("length", 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 ("int length_unit_log = %u;\n", length_unit_log);
}
static rtx
simplify_cond (exp, insn_code, insn_index)
rtx exp;
int insn_code, insn_index;
{
int i, j;
rtx defval = XEXP (exp, 1);
rtx new_defval = XEXP (exp, 1);
int len = XVECLEN (exp, 0);
rtunion *tests = (rtunion *) alloca (len * sizeof (rtunion));
int allsame = 1;
char *first_spacer;
first_spacer = (char *) obstack_finish (rtl_obstack);
bcopy ((char *) XVEC (exp, 0)->elem, (char *) tests, len * sizeof (rtunion));
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 (tests[i].rtx, insn_code, insn_index);
tests[i].rtx = newtest;
newval = tests[i + 1].rtx;
if (GET_CODE (newval) == COND)
newval = simplify_cond (newval, insn_code, insn_index);
if (newtest == true_rtx)
{
len = i;
defval = tests[i + 1].rtx;
new_defval = newval;
}
else if (newtest == false_rtx)
{
for (j = i; j < len - 2; j++)
tests[j].rtx = tests[j + 2].rtx;
len -= 2;
}
else if (i > 0 && attr_equal_p (newval, tests[i - 1].rtx))
{
tests[i - 2].rtx
= insert_right_side (IOR, tests[i - 2].rtx, newtest,
insn_code, insn_index);
for (j = i; j < len - 2; j++)
tests[j].rtx = tests[j + 2].rtx;
len -= 2;
}
else
tests[i + 1].rtx = newval;
}
while (len > 0 && attr_equal_p (tests[len - 1].rtx, 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].rtx, XVECEXP (exp, 0, i)))
{
allsame = 0;
break;
}
if (len == 0)
{
obstack_free (rtl_obstack, first_spacer);
if (GET_CODE (defval) == COND)
return simplify_cond (defval, insn_code, insn_index);
return defval;
}
else if (allsame)
{
obstack_free (rtl_obstack, first_spacer);
return exp;
}
else
{
rtx newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (len);
bcopy ((char *) tests, (char *) XVEC (newexp, 0)->elem,
len * sizeof (rtunion));
XEXP (newexp, 1) = new_defval;
return newexp;
}
}
static void
remove_insn_ent (av, ie)
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->insn_code == -1)
av->has_asm_insn = 0;
num_insn_ents--;
}
static void
insert_insn_ent (av, ie)
struct attr_value *av;
struct insn_ent *ie;
{
ie->next = av->first_insn;
av->first_insn = ie;
av->num_insns++;
if (ie->insn_code == -1)
av->has_asm_insn = 1;
num_insn_ents++;
}
static rtx
insert_right_side (code, exp, term, insn_code, insn_index)
enum rtx_code code;
rtx exp;
rtx term;
int insn_code, 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 (newexp, insn_code, insn_index);
}
static int
compute_alternative_mask (exp, code)
rtx exp;
enum rtx_code code;
{
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
return 0;
if (string[1] == 0)
return 1 << (string[0] - '0');
return 1 << atoi (string);
}
static rtx
make_alternative_compare (mask)
int mask;
{
rtx newexp;
int i;
for (i = 0; (mask & (1 << i)) == 0; i++)
;
newexp = attr_rtx (EQ_ATTR, alternative_name, attr_numeral (i));
RTX_UNCHANGING_P (newexp) = 1;
return newexp;
}
static rtx
evaluate_eq_attr (exp, value, insn_code, insn_index)
rtx exp;
rtx value;
int insn_code, insn_index;
{
rtx orexp, andexp;
rtx right;
rtx newexp;
int i;
if (GET_CODE (value) == CONST_STRING)
{
if (! strcmp (XSTR (value, 0), XSTR (exp, 1)))
newexp = true_rtx;
else
newexp = false_rtx;
}
else if (GET_CODE (value) == SYMBOL_REF)
{
char *p, *string;
if (GET_CODE (exp) != EQ_ATTR)
abort();
string = (char *) alloca (2 + strlen (XSTR (exp, 0))
+ strlen (XSTR (exp, 1)));
strcpy (string, XSTR (exp, 0));
strcat (string, "_");
strcat (string, XSTR (exp, 1));
for (p = string; *p ; p++)
if (*p >= 'a' && *p <= 'z')
*p -= 'a' - 'A';
newexp = attr_rtx (EQ, value,
attr_rtx (SYMBOL_REF,
attr_string(string, strlen(string))));
}
else if (GET_CODE (value) == COND)
{
orexp = false_rtx;
andexp = true_rtx;
if (current_alternative_string)
clear_struct_flag (value);
for (i = 0; i < XVECLEN (value, 0); i += 2)
{
rtx this = SIMPLIFY_TEST_EXP (XVECEXP (value, 0, i),
insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (this);
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);
}
else
abort ();
address_used = 0;
walk_attr_value (newexp);
if (address_used)
{
if (! RTX_UNCHANGING_P (exp))
return copy_rtx_unchanging (exp);
return exp;
}
else
return newexp;
}
static rtx
simplify_and_tree (exp, pterm, insn_code, insn_index)
rtx exp;
rtx *pterm;
int insn_code, 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 (GET_CODE (exp), left, right);
exp = SIMPLIFY_TEST_EXP (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 (GET_CODE (exp), left, right);
exp = SIMPLIFY_TEST_EXP (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 && GET_CODE (*pterm) == EQ_ATTR)
{
if (XSTR (exp, 0) != XSTR (*pterm, 0))
return exp;
if (! strcmp (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 (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 (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 (exp, pterm, insn_code, insn_index)
rtx exp;
rtx *pterm;
int insn_code, 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 (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 (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 rtx
simplify_test_exp (exp, insn_code, insn_index)
rtx exp;
int insn_code, insn_index;
{
rtx left, right;
struct attr_desc *attr;
struct attr_value *av;
struct insn_ent *ie;
int i;
rtx newexp = exp;
char *spacer = (char *) obstack_finish (rtl_obstack);
if (RTX_UNCHANGING_P (exp) || MEM_IN_STRUCT_P (exp))
return exp;
switch (GET_CODE (exp))
{
case AND:
left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (left);
if (left == false_rtx)
{
obstack_free (rtl_obstack, spacer);
return false_rtx;
}
right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (right);
if (left == false_rtx)
{
obstack_free (rtl_obstack, spacer);
return false_rtx;
}
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)
{
obstack_free (rtl_obstack, spacer);
return false_rtx;
}
else if (left == true_rtx)
{
return right;
}
else if (right == true_rtx)
{
return left;
}
else if (insn_code >= 0
&& (GET_CODE (left) == AND
|| (GET_CODE (left) == NOT
&& GET_CODE (XEXP (left, 0)) == EQ_ATTR
&& XSTR (XEXP (left, 0), 0) == alternative_name)
|| GET_CODE (right) == AND
|| (GET_CODE (right) == NOT
&& GET_CODE (XEXP (right, 0)) == EQ_ATTR
&& XSTR (XEXP (right, 0), 0) == alternative_name)))
{
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);
SIMPLIFY_ALTERNATIVE (left);
if (left == true_rtx)
{
obstack_free (rtl_obstack, spacer);
return true_rtx;
}
right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (right);
if (right == true_rtx)
{
obstack_free (rtl_obstack, spacer);
return true_rtx;
}
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)
{
obstack_free (rtl_obstack, spacer);
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
&& XSTR (left, 0) == alternative_name)
|| GET_CODE (right) == IOR
|| (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);
SIMPLIFY_ALTERNATIVE (left);
return left;
}
left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (left);
if (GET_CODE (left) == NOT)
return XEXP (left, 0);
if (left == false_rtx)
{
obstack_free (rtl_obstack, spacer);
return true_rtx;
}
else if (left == true_rtx)
{
obstack_free (rtl_obstack, spacer);
return false_rtx;
}
else 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:
if (current_alternative_string && XSTR (exp, 0) == alternative_name)
return (XSTR (exp, 1) == current_alternative_string
? true_rtx : false_rtx);
if (XSTR (exp, 0) != alternative_name
&& (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->insn_code == insn_code)
return evaluate_eq_attr (exp, av->value, insn_code, insn_index);
break;
default:
break;
}
if (insn_code != -2
&& ! RTX_UNCHANGING_P (newexp))
return copy_rtx_unchanging (newexp);
return newexp;
}
static void
optimize_attrs ()
{
struct attr_desc *attr;
struct attr_value *av;
struct insn_ent *ie;
rtx newexp;
int something_changed = 1;
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
= (struct attr_value_list **) alloca ((insn_code_number + 2)
* sizeof (struct attr_value_list *));
bzero ((char *) insn_code_values,
(insn_code_number + 2) * sizeof (struct attr_value_list *));
insn_code_values += 2;
iv = ivbuf = ((struct attr_value_list *)
xmalloc (num_insn_ents * sizeof (struct attr_value_list)));
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
for (av = attr->first_value; av; av = av->next)
for (ie = av->first_insn; ie; ie = ie->next)
{
iv->attr = attr;
iv->av = av;
iv->ie = ie;
iv->next = insn_code_values[ie->insn_code];
insn_code_values[ie->insn_code] = iv;
iv++;
}
if (iv != ivbuf + num_insn_ents)
abort ();
for (i = -2; i < insn_code_number; i++)
{
for (iv = insn_code_values[i]; iv; iv = iv->next)
clear_struct_flag (iv->av->value);
something_changed = 1;
while (something_changed)
{
something_changed = 0;
for (iv = insn_code_values[i]; iv; iv = iv->next)
{
struct obstack *old = rtl_obstack;
char *spacer = (char *) obstack_finish (temp_obstack);
attr = iv->attr;
av = iv->av;
ie = iv->ie;
if (GET_CODE (av->value) != COND)
continue;
rtl_obstack = temp_obstack;
#if 0
if (insn_n_alternatives[ie->insn_code] > 6
&& count_sub_rtxs (av->value, 200) >= 200)
newexp = simplify_by_alternatives (av->value, ie->insn_code,
ie->insn_index);
else
#endif
newexp = simplify_cond (av->value, ie->insn_code,
ie->insn_index);
rtl_obstack = old;
if (newexp != av->value)
{
newexp = attr_copy_rtx (newexp);
remove_insn_ent (av, ie);
av = get_attr_value (newexp, attr, ie->insn_code);
iv->av = av;
insert_insn_ent (av, ie);
something_changed = 1;
}
obstack_free (temp_obstack, spacer);
}
}
}
free (ivbuf);
}
#if 0
static rtx
simplify_by_alternatives (exp, insn_code, insn_index)
rtx exp;
int insn_code, insn_index;
{
int i;
int len = insn_n_alternatives[insn_code];
rtx newexp = rtx_alloc (COND);
rtx ultimate;
XVEC (newexp, 0) = rtvec_alloc (len * 2);
for (ultimate = exp; GET_CODE (ultimate) == COND;)
ultimate = XEXP (ultimate, 1);
XEXP (newexp, 1) = ultimate;
for (i = 0; i < insn_n_alternatives[insn_code]; i++)
{
current_alternative_string = attr_numeral (i);
XVECEXP (newexp, 0, i * 2) = make_alternative_compare (1 << i);
XVECEXP (newexp, 0, i * 2 + 1)
= simplify_cond (exp, insn_code, insn_index);
}
current_alternative_string = 0;
return simplify_cond (newexp, insn_code, insn_index);
}
#endif
static rtx
simplify_by_exploding (exp)
rtx exp;
{
rtx list = 0, link, condexp, defval = NULL_RTX;
struct dimension *space;
rtx *condtest, *condval;
int i, j, total, ndim = 0;
int most_tests, num_marks, new_marks;
if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0)
{
unmark_used_attributes (list, 0, 0);
return exp;
}
space = (struct dimension *) alloca (ndim * sizeof (struct dimension));
total = 1;
for (ndim = 0; list; ndim++)
{
char *name = XSTR (XEXP (list, 0), 0);
rtx *prev;
if ((space[ndim].attr = find_attr (name, 0)) == 0
|| space[ndim].attr->is_numeric)
{
unmark_used_attributes (list, space, ndim);
return exp;
}
space[ndim].num_values = 0;
space[ndim].values = 0;
prev = &list;
for (link = list; link; link = *prev)
if (! strcmp (XSTR (XEXP (link, 0), 0), name))
{
space[ndim].num_values++;
*prev = XEXP (link, 1);
XEXP (link, 1) = space[ndim].values;
space[ndim].values = link;
}
else
prev = &XEXP (link, 1);
total *= add_values_to_cover (&space[ndim]);
}
for (i = 0; i < ndim; i++)
for (j = ndim - 1; j > i; j--)
if ((space[j-1].attr->is_const && !space[j].attr->is_const)
|| space[j-1].num_values < space[j].num_values)
{
struct dimension tmp;
tmp = space[j];
space[j] = space[j-1];
space[j-1] = tmp;
}
for (i = 0; i < ndim; i++)
space[i].current_value = space[i].values;
condtest = (rtx *) alloca (total * sizeof (rtx));
condval = (rtx *) alloca (total * sizeof (rtx));
for (i = 0;; i++)
{
condtest[i] = test_for_current_value (space, ndim);
condval[i] = simplify_with_current_value (exp, space, ndim);
if (! increment_current_value (space, ndim))
break;
}
if (i != total - 1)
abort ();
unmark_used_attributes (0, space, ndim);
most_tests = -1;
for (i = num_marks = 0; i < total; i++)
if (GET_CODE (condval[i]) == CONST_STRING
&& ! MEM_VOLATILE_P (condval[i]))
{
MEM_VOLATILE_P (condval[i]) = 1;
for (j = new_marks = 0; j < total; j++)
if (GET_CODE (condval[j]) == CONST_STRING
&& MEM_VOLATILE_P (condval[j]))
new_marks++;
if (new_marks - num_marks > most_tests)
{
most_tests = new_marks - num_marks;
defval = condval[i];
}
num_marks = new_marks;
}
for (i = 0; i < total; i++)
MEM_VOLATILE_P (condval[i]) = 0;
if (num_marks == 0)
return exp;
if (total == most_tests)
return defval;
condexp = rtx_alloc (COND);
XVEC (condexp, 0) = rtvec_alloc ((total - most_tests) * 2);
XEXP (condexp, 1) = defval;
for (i = j = 0; i < total; i++)
if (condval[i] != defval)
{
XVECEXP (condexp, 0, 2 * j) = condtest[i];
XVECEXP (condexp, 0, 2 * j + 1) = condval[i];
j++;
}
return condexp;
}
static int
find_and_mark_used_attributes (exp, terms, nterms)
rtx exp, *terms;
int *nterms;
{
int i;
switch (GET_CODE (exp))
{
case EQ_ATTR:
if (! MEM_VOLATILE_P (exp))
{
rtx link = rtx_alloc (EXPR_LIST);
XEXP (link, 0) = exp;
XEXP (link, 1) = *terms;
*terms = link;
*nterms += 1;
MEM_VOLATILE_P (exp) = 1;
}
return 1;
case CONST_STRING:
case CONST_INT:
return 1;
case IF_THEN_ELSE:
if (! find_and_mark_used_attributes (XEXP (exp, 2), terms, nterms))
return 0;
case IOR:
case AND:
if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
return 0;
case NOT:
if (! find_and_mark_used_attributes (XEXP (exp, 0), terms, nterms))
return 0;
return 1;
case COND:
for (i = 0; i < XVECLEN (exp, 0); i++)
if (! find_and_mark_used_attributes (XVECEXP (exp, 0, i), terms, nterms))
return 0;
if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
return 0;
return 1;
default:
return 0;
}
}
static void
unmark_used_attributes (list, space, ndim)
rtx list;
struct dimension *space;
int ndim;
{
rtx link, exp;
int i;
for (i = 0; i < ndim; i++)
unmark_used_attributes (space[i].values, 0, 0);
for (link = list; link; link = XEXP (link, 1))
{
exp = XEXP (link, 0);
if (GET_CODE (exp) == EQ_ATTR)
MEM_VOLATILE_P (exp) = 0;
}
}
static int
add_values_to_cover (dim)
struct dimension *dim;
{
struct attr_value *av;
rtx exp, link, *prev;
int nalt = 0;
for (av = dim->attr->first_value; av; av = av->next)
if (GET_CODE (av->value) == CONST_STRING)
nalt++;
if (nalt < dim->num_values)
abort ();
else if (nalt == dim->num_values)
;
else if (nalt * 2 < dim->num_values * 3)
{
prev = &dim->values;
for (link = dim->values; link; link = *prev)
prev = &XEXP (link, 1);
for (av = dim->attr->first_value; av; av = av->next)
if (GET_CODE (av->value) == CONST_STRING)
{
exp = attr_eq (dim->attr->name, XSTR (av->value, 0));
if (MEM_VOLATILE_P (exp))
continue;
link = rtx_alloc (EXPR_LIST);
XEXP (link, 0) = exp;
XEXP (link, 1) = 0;
*prev = link;
prev = &XEXP (link, 1);
}
dim->num_values = nalt;
}
else
{
rtx orexp = false_rtx;
prev = &dim->values;
for (link = dim->values; link; link = *prev)
{
orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2, -2);
prev = &XEXP (link, 1);
}
link = rtx_alloc (EXPR_LIST);
XEXP (link, 0) = attr_rtx (NOT, orexp);
XEXP (link, 1) = 0;
*prev = link;
dim->num_values++;
}
return dim->num_values;
}
static int
increment_current_value (space, ndim)
struct dimension *space;
int ndim;
{
int i;
for (i = ndim - 1; i >= 0; i--)
{
if ((space[i].current_value = XEXP (space[i].current_value, 1)) == 0)
space[i].current_value = space[i].values;
else
return 1;
}
return 0;
}
static rtx
test_for_current_value (space, ndim)
struct dimension *space;
int ndim;
{
int i;
rtx exp = true_rtx;
for (i = 0; i < ndim; i++)
exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0),
-2, -2);
return exp;
}
static rtx
simplify_with_current_value (exp, space, ndim)
rtx exp;
struct dimension *space;
int ndim;
{
int i;
rtx x;
for (i = 0; i < ndim; i++)
{
x = XEXP (space[i].current_value, 0);
if (GET_CODE (x) == EQ_ATTR)
MEM_VOLATILE_P (x) = 0;
}
exp = simplify_with_current_value_aux (exp);
for (i = 0; i < ndim; i++)
{
x = XEXP (space[i].current_value, 0);
if (GET_CODE (x) == EQ_ATTR)
MEM_VOLATILE_P (x) = 1;
}
return exp;
}
static rtx
simplify_with_current_value_aux (exp)
rtx exp;
{
register int i;
rtx cond;
switch (GET_CODE (exp))
{
case EQ_ATTR:
if (MEM_VOLATILE_P (exp))
return false_rtx;
else
return true_rtx;
case CONST_STRING:
case CONST_INT:
return exp;
case IF_THEN_ELSE:
cond = simplify_with_current_value_aux (XEXP (exp, 0));
if (cond == true_rtx)
return simplify_with_current_value_aux (XEXP (exp, 1));
else if (cond == false_rtx)
return simplify_with_current_value_aux (XEXP (exp, 2));
else
return attr_rtx (IF_THEN_ELSE, cond,
simplify_with_current_value_aux (XEXP (exp, 1)),
simplify_with_current_value_aux (XEXP (exp, 2)));
case IOR:
cond = simplify_with_current_value_aux (XEXP (exp, 1));
if (cond == true_rtx)
return cond;
else if (cond == false_rtx)
return simplify_with_current_value_aux (XEXP (exp, 0));
else
return attr_rtx (IOR, cond,
simplify_with_current_value_aux (XEXP (exp, 0)));
case AND:
cond = simplify_with_current_value_aux (XEXP (exp, 1));
if (cond == true_rtx)
return simplify_with_current_value_aux (XEXP (exp, 0));
else if (cond == false_rtx)
return cond;
else
return attr_rtx (AND, cond,
simplify_with_current_value_aux (XEXP (exp, 0)));
case NOT:
cond = simplify_with_current_value_aux (XEXP (exp, 0));
if (cond == true_rtx)
return false_rtx;
else if (cond == false_rtx)
return true_rtx;
else
return attr_rtx (NOT, cond);
case COND:
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
cond = simplify_with_current_value_aux (XVECEXP (exp, 0, i));
if (cond == true_rtx)
return simplify_with_current_value_aux (XVECEXP (exp, 0, i + 1));
else if (cond == false_rtx)
continue;
else
abort ();
}
return simplify_with_current_value_aux (XEXP (exp, 1));
default:
abort ();
}
}
static void
clear_struct_flag (x)
rtx x;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
MEM_IN_STRUCT_P (x) = 0;
if (RTX_UNCHANGING_P (x))
return;
code = GET_CODE (x);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
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 int
count_sub_rtxs (x, max)
rtx x;
int max;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
int total = 0;
code = GET_CODE (x);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case EQ_ATTR:
case ATTR_FLAG:
return 1;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (total >= max)
return total;
switch (fmt[i])
{
case 'V':
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
total += count_sub_rtxs (XVECEXP (x, i, j), max);
break;
case 'e':
total += count_sub_rtxs (XEXP (x, i), max);
break;
}
}
return total;
}
static void
gen_attr (exp)
rtx exp;
{
struct attr_desc *attr;
struct attr_value *av;
char *name_ptr;
char *p;
attr = find_attr (XSTR (exp, 0), 1);
if (attr->default_val)
fatal ("Duplicate definition for `%s' attribute", attr->name);
if (*XSTR (exp, 1) == '\0')
attr->is_numeric = 1;
else
{
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
av = (struct attr_value *) 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)
fatal ("Constant attributes may not take numeric values");
XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
}
if (! strcmp (attr->name, "length") && ! attr->is_numeric)
fatal ("`length' attribute must take numeric values");
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 (exp)
rtx exp;
{
int i, j, n;
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 (exp)
rtx exp;
{
int i, j;
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 (inner, exp)
rtx inner;
rtx exp;
{
int i, j;
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 (exp)
rtx exp;
{
struct insn_def *id;
id = (struct insn_def *) oballoc (sizeof (struct insn_def));
id->next = defs;
defs = id;
id->def = exp;
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:
abort ();
}
}
static void
gen_delay (def)
rtx def;
{
struct delay_desc *delay;
int i;
if (XVECLEN (def, 1) % 3 != 0)
fatal ("Number of elements in DEFINE_DELAY must be multiple of three.");
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 = (struct delay_desc *) oballoc (sizeof (struct delay_desc));
delay->def = def;
delay->num = ++num_delays;
delay->next = delays;
delays = delay;
}
static void
gen_unit (def)
rtx def;
{
struct function_unit *unit;
struct function_unit_op *op;
char *name = XSTR (def, 0);
int multiplicity = XINT (def, 1);
int simultaneity = XINT (def, 2);
rtx condexp = XEXP (def, 3);
int ready_cost = MAX (XINT (def, 4), 1);
int issue_delay = MAX (XINT (def, 5), 1);
for (unit = units; unit; unit = unit->next)
if (! strcmp (unit->name, name))
{
if (unit->multiplicity != multiplicity
|| unit->simultaneity != simultaneity)
fatal ("Differing specifications given for `%s' function unit.",
unit->name);
break;
}
if (unit == 0)
{
unit = (struct function_unit *) oballoc (sizeof (struct function_unit));
unit->name = name;
unit->multiplicity = multiplicity;
unit->simultaneity = simultaneity;
unit->issue_delay.min = unit->issue_delay.max = issue_delay;
unit->num = num_units++;
unit->num_opclasses = 0;
unit->condexp = false_rtx;
unit->ops = 0;
unit->next = units;
units = unit;
}
op = (struct function_unit_op *) oballoc (sizeof (struct function_unit_op));
op->condexp = condexp;
op->num = unit->num_opclasses++;
op->ready = ready_cost;
op->issue_delay = issue_delay;
op->next = unit->ops;
unit->ops = op;
num_unit_opclasses++;
if (XVEC (def, 6))
{
rtx orexp = false_rtx;
int i;
for (i = 0; i < XVECLEN (def, 6); i++)
orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2, -2);
op->conflict_exp = orexp;
extend_range (&unit->issue_delay, 1, issue_delay);
}
else
{
op->conflict_exp = true_rtx;
extend_range (&unit->issue_delay, issue_delay, issue_delay);
}
unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2);
}
static void
write_test_expr (exp, flags)
rtx exp;
int flags;
{
int comparison_operator = 0;
RTX_CODE code;
struct attr_desc *attr;
printf ("(");
code = GET_CODE (exp);
switch (code)
{
case EQ: case NE:
case GE: case GT: case GEU: case GTU:
case LE: case LT: case LEU: case LTU:
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:
abort ();
}
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:
abort ();
}
write_test_expr (XEXP (exp, 0), flags);
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);
if (! attr) abort ();
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 MATCH_INSN:
printf ("%s (insn)", XSTR (exp, 0));
break;
case CONST_INT:
printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
break;
case SYMBOL_REF:
printf ("%s", XSTR (exp, 0));
break;
case MATCH_DUP:
printf ("insn_addresses[INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])]",
XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
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 (exp, unknownp)
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
or_attr_value (exp, unknownp)
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 (exp)
rtx exp;
{
register int i, j;
register char *fmt;
RTX_CODE code;
if (exp == NULL)
return;
code = GET_CODE (exp);
switch (code)
{
case SYMBOL_REF:
if (! RTX_UNCHANGING_P (exp))
must_extract = must_constrain = 1;
return;
case MATCH_OPERAND:
must_extract = 1;
return;
case EQ_ATTR:
if (XSTR (exp, 0) == alternative_name)
must_extract = must_constrain = 1;
else if (strcmp (XSTR (exp, 0), "length") == 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 (attr)
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 if (attr->unsigned_p)
printf ("unsigned int\n");
else
printf ("int\n");
if (attr->name[0] == '*')
printf ("%s (insn)\n", &attr->name[1]);
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");
if (GET_CODE (common_av->value) == FFS)
{
rtx p = XEXP (common_av->value, 0);
write_toplevel_expr (p);
printf ("\n if (accum && accum == (accum & -accum))\n");
printf (" {\n");
printf (" int i;\n");
printf (" for (i = 0; accum >>= 1; ++i) continue;\n");
printf (" accum = i;\n");
printf (" }\n else\n");
printf (" accum = ~accum;\n");
printf (" return accum;\n}\n\n");
}
else
{
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 (known_true, exp, insn_code, insn_index)
rtx known_true;
rtx exp;
int insn_code, 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 (attr, indent, value, prefix, suffix, known_true,
insn_code, insn_index)
struct attr_desc *attr;
int indent;
rtx value;
const char *prefix;
const char *suffix;
rtx known_true;
int insn_code, 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_attr_case (attr, av, write_case_lines, prefix, suffix, indent,
known_true)
struct attr_desc *attr;
struct attr_value *av;
int write_case_lines;
const char *prefix, *suffix;
int indent;
rtx known_true;
{
struct insn_ent *ie;
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)
{
for (ie = av->first_insn; ie; ie = ie->next)
if (ie->insn_code != -1)
{
write_indent (indent);
printf ("case %d:\n", ie->insn_code);
}
}
else
{
write_indent (indent);
printf ("default:\n");
}
must_extract = must_constrain = address_used = 0;
walk_attr_value (av->value);
if (must_extract)
{
write_indent (indent + 2);
printf ("extract_insn (insn);\n");
}
if (must_constrain)
{
#ifdef REGISTER_CONSTRAINTS
write_indent (indent + 2);
printf ("if (! constrain_operands (reload_completed))\n");
write_indent (indent + 2);
printf (" fatal_insn_not_found (insn);\n");
#endif
}
write_attr_set (attr, indent + 2, av->value, prefix, suffix,
known_true, av->first_insn->insn_code,
av->first_insn->insn_index);
if (strncmp (prefix, "return", 6))
{
write_indent (indent + 2);
printf ("break;\n");
}
printf ("\n");
}
static int
write_expr_attr_cache (p, attr)
rtx p;
struct attr_desc *attr;
{
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 (" register enum attr_%s ", attr->name);
else if (attr->unsigned_p)
printf (" register unsigned int ");
else
printf (" register 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_toplevel_expr (p)
rtx p;
{
struct attr_desc *attr;
int i;
for (i = 0; i < MAX_ATTRS_INDEX; ++i)
for (attr = attrs[i]; attr ; attr = attr->next)
if (!attr->is_const)
write_expr_attr_cache (p, attr);
printf(" register unsigned long accum = 0;\n\n");
while (GET_CODE (p) == IOR)
{
rtx e;
if (GET_CODE (XEXP (p, 0)) == IOR)
e = XEXP (p, 1), p = XEXP (p, 0);
else
e = XEXP (p, 0), p = XEXP (p, 1);
printf (" accum |= ");
write_test_expr (e, 3);
printf (";\n");
}
printf (" accum |= ");
write_test_expr (p, 3);
printf (";\n");
}
static void
write_unit_name (prefix, num, suffix)
const char *prefix;
int num;
const char *suffix;
{
struct function_unit *unit;
for (unit = units; unit; unit = unit->next)
if (unit->num == num)
{
printf ("%s%s%s", prefix, unit->name, suffix);
return;
}
printf ("%s<unknown>%s", prefix, suffix);
}
static void
write_attr_valueq (attr, s)
struct attr_desc *attr;
char *s;
{
if (attr->is_numeric)
{
int num = atoi (s);
printf ("%d", num);
if (attr->func_units_p)
{
if (num == -1)
printf (" /* units: none */");
else if (num >= 0)
write_unit_name (" /* units: ", num, " */");
else
{
int i;
const char *sep = " /* units: ";
for (i = 0, num = ~num; num; i++, num >>= 1)
if (num & 1)
{
write_unit_name (sep, i, (num == 1) ? " */" : "");
sep = ", ";
}
}
}
else if (attr->blockage_p)
printf (" /* min %d, max %d */", num >> (HOST_BITS_PER_INT / 2),
num & ((1 << (HOST_BITS_PER_INT / 2)) - 1));
else if (num > 9 || num < 0)
printf (" /* 0x%x */", num);
}
else
{
write_upcase (attr->name);
printf ("_");
write_upcase (s);
}
}
static void
write_attr_value (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 SYMBOL_REF:
fputs (XSTR (value, 0), stdout);
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:
abort ();
}
}
static void
write_upcase (str)
char *str;
{
while (*str)
if (*str < 'a' || *str > 'z')
printf ("%c", *str++);
else
printf ("%c", *str++ - 'a' + 'A');
}
static void
write_indent (indent)
int indent;
{
for (; indent > 8; indent -= 8)
printf ("\t");
for (; indent; indent--)
printf (" ");
}
static void
write_eligible_delay (kind)
const char *kind;
{
struct delay_desc *delay;
int max_slots;
char str[50];
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 (delay_insn, slot, candidate_insn, flags)\n",
kind);
printf (" rtx delay_insn;\n");
printf (" int slot;\n");
printf (" rtx candidate_insn;\n");
printf (" int flags;\n");
printf ("{\n");
printf (" rtx insn;\n");
printf ("\n");
printf (" if (slot >= %d)\n", max_slots);
printf (" abort ();\n");
printf ("\n");
if (num_delays > 1)
{
attr = find_attr ("*delay_type", 0);
if (! attr) abort ();
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 (" if (slot < %d)\n", max_slots);
printf (" abort ();\n\n");
}
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", 0);
if (! attr) abort ();
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);
attr = find_attr (str, 0);
if (! attr) abort ();
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 (" abort ();\n");
printf (" }\n");
}
printf ("}\n\n");
}
static void
write_function_unit_info ()
{
struct function_unit *unit;
int i;
for (unit = units; unit; unit = unit->next)
{
if (unit->needs_blockage_function)
write_complex_function (unit, "blockage", "block");
if (! unit->needs_conflict_function)
{
unit->default_cost = make_numeric_value (unit->issue_delay.max);
continue;
}
unit->default_cost = make_numeric_value (0);
write_complex_function (unit, "conflict_cost", "cost");
}
printf ("struct function_unit_desc function_units[] = {\n");
for (i = 0; i < num_units; i++)
{
for (unit = units; unit; unit = unit->next)
if (unit->num == i)
break;
printf (" {\"%s\", %d, %d, %d, %s, %d, %s_unit_ready_cost, ",
unit->name, 1 << unit->num, unit->multiplicity,
unit->simultaneity, XSTR (unit->default_cost, 0),
unit->issue_delay.max, unit->name);
if (unit->needs_conflict_function)
printf ("%s_unit_conflict_cost, ", unit->name);
else
printf ("0, ");
printf ("%d, ", unit->max_blockage);
if (unit->needs_range_function)
printf ("%s_unit_blockage_range, ", unit->name);
else
printf ("0, ");
if (unit->needs_blockage_function)
printf ("%s_unit_blockage", unit->name);
else
printf ("0");
printf ("}, \n");
}
printf ("};\n\n");
}
static void
write_complex_function (unit, name, connection)
struct function_unit *unit;
const char *name, *connection;
{
struct attr_desc *case_attr, *attr;
struct attr_value *av, *common_av;
rtx value;
char *str;
int using_case;
int i;
printf ("static int\n");
printf ("%s_unit_%s (executing_insn, candidate_insn)\n",
unit->name, name);
printf (" rtx executing_insn;\n");
printf (" rtx candidate_insn;\n");
printf ("{\n");
printf (" rtx insn;\n");
printf (" int casenum;\n\n");
printf (" insn = executing_insn;\n");
printf (" switch (recog_memoized (insn))\n");
printf (" {\n");
str = (char *) alloca (strlen (unit->name) + strlen (name) + strlen (connection) + 10);
sprintf (str, "*%s_cases", unit->name);
case_attr = find_attr (str, 0);
if (! case_attr) abort ();
common_av = find_most_used (case_attr);
for (av = case_attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (case_attr, av, 1,
"casenum =", ";", 4, unit->condexp);
write_attr_case (case_attr, common_av, 0,
"casenum =", ";", 4, unit->condexp);
printf (" }\n\n");
printf (" insn = candidate_insn;\n");
printf (" switch (casenum)\n");
printf (" {\n");
for (i = 0; i < unit->num_opclasses; i++)
{
using_case = 0;
for (av = case_attr->first_value; av; av = av->next)
if (av->num_insns
&& contained_in_p (make_numeric_value (i), av->value))
using_case = 1;
if (! using_case)
continue;
printf (" case %d:\n", i);
sprintf (str, "*%s_%s_%d", unit->name, connection, i);
attr = find_attr (str, 0);
if (! attr) abort ();
value = find_single_value (attr);
if (value)
write_attr_set (attr, 6, value, "return", ";\n", true_rtx, -2, -2);
else
{
common_av = find_most_used (attr);
printf (" switch (recog_memoized (insn))\n");
printf ("\t{\n");
for (av = attr->first_value; av; av = av->next)
if (av != common_av)
write_attr_case (attr, av, 1,
"return", ";", 8, unit->condexp);
write_attr_case (attr, common_av, 0,
"return", ";", 8, unit->condexp);
printf (" }\n\n");
}
}
printf (" default:\n abort ();\n");
printf (" }\n}\n\n");
}
static int
n_comma_elts (s)
char *s;
{
int n;
if (*s == '\0')
return 0;
for (n = 1; *s; s++)
if (*s == ',')
n++;
return n;
}
static char *
next_comma_elt (pstr)
char **pstr;
{
char *out_str;
char *p;
if (**pstr == '\0')
return NULL;
for (p = *pstr; *p != ',' && *p != '\0'; p++)
;
out_str = attr_string (*pstr, p - *pstr);
*pstr = p;
if (**pstr == ',')
(*pstr)++;
return out_str;
}
static struct attr_desc *
find_attr (name, create)
const char *name;
int create;
{
struct attr_desc *attr;
int index;
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))
return attr;
if (! create)
return NULL;
attr = (struct attr_desc *) oballoc (sizeof (struct attr_desc));
attr->name = attr_string (name, strlen (name));
attr->first_value = attr->default_val = NULL;
attr->is_numeric = attr->negative_ok = attr->is_const = attr->is_special = 0;
attr->next = attrs[index];
attrs[index] = attr;
return attr;
}
static void
make_internal_attr (name, value, special)
const char *name;
rtx value;
int special;
{
struct attr_desc *attr;
attr = find_attr (name, 1);
if (attr->default_val)
abort ();
attr->is_numeric = 1;
attr->is_const = 0;
attr->is_special = (special & 1) != 0;
attr->negative_ok = (special & 2) != 0;
attr->unsigned_p = (special & 4) != 0;
attr->func_units_p = (special & 8) != 0;
attr->blockage_p = (special & 16) != 0;
attr->default_val = get_attr_value (value, attr, -2);
}
static struct attr_value *
find_most_used (attr)
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
find_single_value (attr)
struct attr_desc *attr;
{
struct attr_value *av;
rtx unique_value;
unique_value = NULL;
for (av = attr->first_value; av; av = av->next)
if (av->num_insns)
{
if (unique_value)
return NULL;
else
unique_value = av->value;
}
return unique_value;
}
static rtx
make_numeric_value (n)
int n;
{
static rtx int_values[20];
rtx exp;
char *p;
if (n < 0)
abort ();
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 void
extend_range (range, min, max)
struct range *range;
int min;
int max;
{
if (range->min > min) range->min = min;
if (range->max < max) range->max = max;
}
PTR
xrealloc (old, size)
PTR old;
size_t size;
{
register PTR ptr;
if (old)
ptr = (PTR) realloc (old, size);
else
ptr = (PTR) malloc (size);
if (!ptr)
fatal ("virtual memory exhausted");
return ptr;
}
PTR
xmalloc (size)
size_t size;
{
register PTR val = (PTR) malloc (size);
if (val == 0)
fatal ("virtual memory exhausted");
return val;
}
static rtx
copy_rtx_unchanging (orig)
register rtx orig;
{
#if 0
register rtx copy;
register RTX_CODE code;
#endif
if (RTX_UNCHANGING_P (orig) || MEM_IN_STRUCT_P (orig))
return orig;
MEM_IN_STRUCT_P (orig) = 1;
return orig;
#if 0
code = GET_CODE (orig);
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
return orig;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
RTX_UNCHANGING_P (copy) = 1;
bcopy ((char *) &XEXP (orig, 0), (char *) &XEXP (copy, 0),
GET_RTX_LENGTH (GET_CODE (copy)) * sizeof (rtx));
return copy;
#endif
}
void
fatal VPROTO ((const char *format, ...))
{
#ifndef ANSI_PROTOTYPES
const char *format;
#endif
va_list ap;
VA_START (ap, format);
#ifndef ANSI_PROTOTYPES
format = va_arg (ap, const char *);
#endif
fprintf (stderr, "genattrtab: ");
vfprintf (stderr, format, ap);
va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
void
fancy_abort ()
{
fatal ("Internal gcc abort.");
}
void
write_const_num_delay_slots ()
{
struct attr_desc *attr = find_attr ("*num_delay_slots", 0);
struct attr_value *av;
struct insn_ent *ie;
if (attr)
{
printf ("int\nconst_num_delay_slots (insn)\n");
printf (" 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)
{
for (ie = av->first_insn; ie; ie = ie->next)
if (ie->insn_code != -1)
printf (" case %d:\n", ie->insn_code);
printf (" return 0;\n");
}
}
printf (" default:\n");
printf (" return 1;\n");
printf (" }\n}\n\n");
}
}
int
main (argc, argv)
int argc;
char **argv;
{
rtx desc;
FILE *infile;
register int c;
struct attr_desc *attr;
struct insn_def *id;
rtx tem;
int i;
#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT)
{
struct rlimit rlim;
getrlimit (RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit (RLIMIT_STACK, &rlim);
}
#endif
obstack_init (rtl_obstack);
obstack_init (hash_obstack);
obstack_init (temp_obstack);
if (argc <= 1)
fatal ("No input file name.");
infile = fopen (argv[1], "r");
if (infile == 0)
{
perror (argv[1]);
exit (FATAL_EXIT_CODE);
}
init_rtl ();
true_rtx = rtx_alloc (CONST_INT);
XWINT (true_rtx, 0) = 1;
false_rtx = rtx_alloc (CONST_INT);
XWINT (false_rtx, 0) = 0;
RTX_UNCHANGING_P (true_rtx) = RTX_UNCHANGING_P (false_rtx) = 1;
RTX_INTEGRATED_P (true_rtx) = RTX_INTEGRATED_P (false_rtx) = 1;
alternative_name = attr_string ("alternative", strlen ("alternative"));
printf ("/* Generated automatically by the program `genattrtab'\n\
from the machine description file `md'. */\n\n");
while (1)
{
c = read_skip_spaces (infile);
if (c == EOF)
break;
ungetc (c, infile);
desc = read_rtx (infile);
if (GET_CODE (desc) == DEFINE_INSN
|| GET_CODE (desc) == DEFINE_PEEPHOLE
|| GET_CODE (desc) == DEFINE_ASM_ATTRIBUTES)
gen_insn (desc);
else if (GET_CODE (desc) == DEFINE_EXPAND)
insn_code_number++, insn_index_number++;
else if (GET_CODE (desc) == DEFINE_SPLIT)
insn_code_number++, insn_index_number++;
else if (GET_CODE (desc) == DEFINE_ATTR)
{
gen_attr (desc);
insn_index_number++;
}
else if (GET_CODE (desc) == DEFINE_DELAY)
{
gen_delay (desc);
insn_index_number++;
}
else if (GET_CODE (desc) == DEFINE_FUNCTION_UNIT)
{
gen_unit (desc);
insn_index_number++;
}
}
if (! got_define_asm_attributes)
{
tem = rtx_alloc (DEFINE_ASM_ATTRIBUTES);
XVEC (tem, 0) = rtvec_alloc (0);
gen_insn (tem);
}
if (num_delays)
expand_delays ();
if (num_units)
expand_units ();
printf ("#include \"config.h\"\n");
printf ("#include \"system.h\"\n");
printf ("#include \"rtl.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 ("\n");
printf ("#define operands recog_operand\n\n");
insn_alternatives = (int *) 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 = (int *) 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;
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);
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");
}
if (num_units)
write_function_unit_info ();
write_const_num_delay_slots ();
write_length_unit_log ();
fflush (stdout);
exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
return 0;
}