#define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), unchanging))
#define ATTR_CURR_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), in_struct))
#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), integrated))
#define ATTR_EQ_ATTR_P(RTX) (RTX_FLAG((RTX), volatil))
#include "hconfig.h"
#include "system.h"
#include "rtl.h"
#include "ggc.h"
#include "gensupport.h"
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#include "obstack.h"
#include "errors.h"
#include "genattrtab.h"
static struct obstack obstack1, obstack2;
struct obstack *hash_obstack = &obstack1;
struct obstack *temp_obstack = &obstack2;
#define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
struct insn_def
{
struct insn_def *next;
rtx def;
int insn_code;
int insn_index;
int lineno;
int num_alternatives;
int vec_idx;
};
struct insn_ent
{
struct insn_ent *next;
int insn_code;
int insn_index;
int lineno;
};
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;
int lineno;
};
#define NULL_ATTR (struct attr_desc *) NULL
struct range
{
int min;
int max;
};
struct delay_desc
{
rtx def;
struct delay_desc *next;
int num;
int lineno;
};
struct function_unit_op
{
rtx condexp;
struct function_unit_op *next;
int num;
int ready;
int issue_delay;
rtx conflict_exp;
rtx issue_exp;
int lineno;
};
struct function_unit
{
const 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;
int first_lineno;
};
#define MAX_ATTRS_INDEX 256
static struct attr_desc *attrs[MAX_ATTRS_INDEX];
static struct insn_def *defs;
static struct delay_desc *delays;
static 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;
int num_dfa_decls;
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 const 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) \
(ATTR_IND_SIMPLIFIED_P (EXP) || ATTR_CURR_SIMPLIFIED_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);
rtx global_rtl[GR_MAX];
rtx pic_offset_table_rtx;
static void attr_hash_add_rtx PARAMS ((int, rtx));
static void attr_hash_add_string PARAMS ((int, char *));
static rtx attr_rtx PARAMS ((enum rtx_code, ...));
static rtx attr_rtx_1 PARAMS ((enum rtx_code, va_list));
static char *attr_string PARAMS ((const char *, int));
static rtx check_attr_value PARAMS ((rtx, struct attr_desc *));
static rtx convert_set_attr_alternative PARAMS ((rtx, struct insn_def *));
static rtx convert_set_attr PARAMS ((rtx, struct insn_def *));
static void check_defs PARAMS ((void));
#if 0
static rtx convert_const_symbol_ref PARAMS ((rtx, struct attr_desc *));
#endif
static rtx make_canonical PARAMS ((struct attr_desc *, rtx));
static struct attr_value *get_attr_value PARAMS ((rtx, struct attr_desc *, int));
static rtx copy_rtx_unchanging PARAMS ((rtx));
static rtx copy_boolean PARAMS ((rtx));
static void expand_delays PARAMS ((void));
static rtx operate_exp PARAMS ((enum operator, rtx, rtx));
static void expand_units PARAMS ((void));
static rtx simplify_knowing PARAMS ((rtx, rtx));
static rtx encode_units_mask PARAMS ((rtx));
static void fill_attr PARAMS ((struct attr_desc *));
static rtx substitute_address PARAMS ((rtx, rtx (*) (rtx), rtx (*) (rtx)));
static void make_length_attrs PARAMS ((void));
static rtx identity_fn PARAMS ((rtx));
static rtx zero_fn PARAMS ((rtx));
static rtx one_fn PARAMS ((rtx));
static rtx max_fn PARAMS ((rtx));
static void write_length_unit_log PARAMS ((void));
static rtx simplify_cond PARAMS ((rtx, int, int));
#if 0
static rtx simplify_by_alternatives PARAMS ((rtx, int, int));
#endif
static rtx simplify_by_exploding PARAMS ((rtx));
static int find_and_mark_used_attributes PARAMS ((rtx, rtx *, int *));
static void unmark_used_attributes PARAMS ((rtx, struct dimension *, int));
static int add_values_to_cover PARAMS ((struct dimension *));
static int increment_current_value PARAMS ((struct dimension *, int));
static rtx test_for_current_value PARAMS ((struct dimension *, int));
static rtx simplify_with_current_value PARAMS ((rtx, struct dimension *, int));
static rtx simplify_with_current_value_aux PARAMS ((rtx));
static void clear_struct_flag PARAMS ((rtx));
static int count_sub_rtxs PARAMS ((rtx, int));
static void remove_insn_ent PARAMS ((struct attr_value *, struct insn_ent *));
static void insert_insn_ent PARAMS ((struct attr_value *, struct insn_ent *));
static rtx insert_right_side PARAMS ((enum rtx_code, rtx, rtx, int, int));
static rtx make_alternative_compare PARAMS ((int));
static int compute_alternative_mask PARAMS ((rtx, enum rtx_code));
static rtx evaluate_eq_attr PARAMS ((rtx, rtx, int, int));
static rtx simplify_and_tree PARAMS ((rtx, rtx *, int, int));
static rtx simplify_or_tree PARAMS ((rtx, rtx *, int, int));
static rtx simplify_test_exp PARAMS ((rtx, int, int));
static rtx simplify_test_exp_in_temp PARAMS ((rtx, int, int));
static void optimize_attrs PARAMS ((void));
static void gen_attr PARAMS ((rtx, int));
static int count_alternatives PARAMS ((rtx));
static int compares_alternatives_p PARAMS ((rtx));
static int contained_in_p PARAMS ((rtx, rtx));
static void gen_insn PARAMS ((rtx, int));
static void gen_delay PARAMS ((rtx, int));
static void gen_unit PARAMS ((rtx, int));
static void write_test_expr PARAMS ((rtx, int));
static int max_attr_value PARAMS ((rtx, int*));
static int or_attr_value PARAMS ((rtx, int*));
static void walk_attr_value PARAMS ((rtx));
static void write_attr_get PARAMS ((struct attr_desc *));
static rtx eliminate_known_true PARAMS ((rtx, rtx, int, int));
static void write_attr_set PARAMS ((struct attr_desc *, int, rtx,
const char *, const char *, rtx,
int, int));
static void write_attr_case PARAMS ((struct attr_desc *, struct attr_value *,
int, const char *, const char *, int, rtx));
static void write_unit_name PARAMS ((const char *, int, const char *));
static void write_attr_valueq PARAMS ((struct attr_desc *, const char *));
static void write_attr_value PARAMS ((struct attr_desc *, rtx));
static void write_upcase PARAMS ((const char *));
static void write_indent PARAMS ((int));
static void write_eligible_delay PARAMS ((const char *));
static void write_function_unit_info PARAMS ((void));
static void write_complex_function PARAMS ((struct function_unit *, const char *,
const char *));
static int write_expr_attr_cache PARAMS ((rtx, struct attr_desc *));
static void write_toplevel_expr PARAMS ((rtx));
static void write_const_num_delay_slots PARAMS ((void));
static char *next_comma_elt PARAMS ((const char **));
static struct attr_desc *find_attr PARAMS ((const char *, int));
static struct attr_value *find_most_used PARAMS ((struct attr_desc *));
static rtx find_single_value PARAMS ((struct attr_desc *));
static void extend_range PARAMS ((struct range *, int, int));
static rtx attr_eq PARAMS ((const char *, const char *));
static const char *attr_numeral PARAMS ((int));
static int attr_equal_p PARAMS ((rtx, rtx));
static rtx attr_copy_rtx PARAMS ((rtx));
static int attr_rtx_cost PARAMS ((rtx));
#define oballoc(size) obstack_alloc (hash_obstack, size)
struct attr_hash
{
struct attr_hash *next;
int hashcode;
union
{
char *str;
rtx rtl;
} u;
};
#define RTL_HASH_SIZE 4093
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;
{
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;
{
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_1 (code, p)
enum rtx_code code;
va_list p;
{
rtx rt_val = NULL_RTX;
int hashcode;
struct attr_hash *h;
struct obstack *old_obstack = rtl_obstack;
if (GET_RTX_CLASS (code) == '1')
{
rtx arg0 = va_arg (p, rtx);
if (! ATTR_PERMANENT_P (arg0))
{
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
return rt_val;
}
hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0));
for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
&& GET_CODE (h->u.rtl) == code
&& XEXP (h->u.rtl, 0) == arg0)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
}
}
else if (GET_RTX_CLASS (code) == 'c'
|| GET_RTX_CLASS (code) == '2'
|| GET_RTX_CLASS (code) == '<')
{
rtx arg0 = va_arg (p, rtx);
rtx arg1 = va_arg (p, rtx);
if (! ATTR_PERMANENT_P (arg0) || ! ATTR_PERMANENT_P (arg1))
{
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
XEXP (rt_val, 1) = arg1;
return rt_val;
}
hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0) + RTL_HASH (arg1));
for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
&& GET_CODE (h->u.rtl) == code
&& XEXP (h->u.rtl, 0) == arg0
&& XEXP (h->u.rtl, 1) == arg1)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
rt_val = rtx_alloc (code);
XEXP (rt_val, 0) = arg0;
XEXP (rt_val, 1) = arg1;
}
}
else if (GET_RTX_LENGTH (code) == 1
&& GET_RTX_FORMAT (code)[0] == 's')
{
char *arg0 = va_arg (p, char *);
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)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
rt_val = rtx_alloc (code);
XSTR (rt_val, 0) = arg0;
}
}
else if (GET_RTX_LENGTH (code) == 2
&& GET_RTX_FORMAT (code)[0] == 's'
&& GET_RTX_FORMAT (code)[1] == 's')
{
char *arg0 = va_arg (p, char *);
char *arg1 = va_arg (p, char *);
hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0) + RTL_HASH (arg1));
for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
&& GET_CODE (h->u.rtl) == code
&& XSTR (h->u.rtl, 0) == arg0
&& XSTR (h->u.rtl, 1) == arg1)
return h->u.rtl;
if (h == 0)
{
rtl_obstack = hash_obstack;
rt_val = rtx_alloc (code);
XSTR (rt_val, 0) = arg0;
XSTR (rt_val, 1) = arg1;
}
}
else if (code == CONST_INT)
{
HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
if (arg0 == 0)
return false_rtx;
else if (arg0 == 1)
return true_rtx;
else
goto nohash;
}
else
{
int i;
const char *fmt;
nohash:
rt_val = rtx_alloc (code);
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*fmt++)
{
case '0':
break;
case 'i':
XINT (rt_val, i) = va_arg (p, int);
break;
case 'w':
XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
break;
case 's':
XSTR (rt_val, i) = va_arg (p, char *);
break;
case 'e':
case 'u':
XEXP (rt_val, i) = va_arg (p, rtx);
break;
case 'E':
XVEC (rt_val, i) = va_arg (p, rtvec);
break;
default:
abort ();
}
}
return rt_val;
}
rtl_obstack = old_obstack;
attr_hash_add_rtx (hashcode, rt_val);
ATTR_PERMANENT_P (rt_val) = 1;
return rt_val;
}
static rtx
attr_rtx VPARAMS ((enum rtx_code code, ...))
{
rtx result;
VA_OPEN (p, code);
VA_FIXEDARG (p, enum rtx_code, code);
result = attr_rtx_1 (code, p);
VA_CLOSE (p);
return result;
}
char *
attr_printf VPARAMS ((unsigned int len, const char *fmt, ...))
{
char str[256];
VA_OPEN (p, fmt);
VA_FIXEDARG (p, unsigned int, len);
VA_FIXEDARG (p, const char *, fmt);
if (len > sizeof str - 1)
abort ();
vsprintf (str, fmt, p);
VA_CLOSE (p);
return attr_string (str, strlen (str));
}
static rtx
attr_eq (name, value)
const char *name, *value;
{
return attr_rtx (EQ_ATTR, attr_string (name, strlen (name)),
attr_string (value, strlen (value)));
}
static const char *
attr_numeral (n)
int n;
{
return XSTR (make_numeric_value (n), 0);
}
static char *
attr_string (str, len)
const char *str;
int len;
{
struct attr_hash *h;
int hashcode;
int i;
char *new_str;
hashcode = (len + 1) * 613 + (unsigned) str[0];
for (i = 1; i <= len; i += 2)
hashcode = ((hashcode * 613) + (unsigned) str[i]);
if (hashcode < 0)
hashcode = -hashcode;
for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
if (h->hashcode == -hashcode && h->u.str[0] == str[0]
&& !strncmp (h->u.str, str, len))
return h->u.str;
new_str = (char *) obstack_alloc (hash_obstack, len + 1);
memcpy (new_str, str, len);
new_str[len] = '\0';
attr_hash_add_string (hashcode, new_str);
return new_str;
}
static int
attr_equal_p (x, y)
rtx x, y;
{
return (x == y || (! (ATTR_PERMANENT_P (x) && ATTR_PERMANENT_P (y))
&& rtx_equal_p (x, y)));
}
static rtx
attr_copy_rtx (orig)
rtx orig;
{
rtx copy;
int i, j;
RTX_CODE code;
const char *format_ptr;
if (ATTR_PERMANENT_P (orig))
return orig;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
return orig;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
ATTR_IND_SIMPLIFIED_P (copy) = ATTR_IND_SIMPLIFIED_P (orig);
ATTR_CURR_SIMPLIFIED_P (copy) = ATTR_CURR_SIMPLIFIED_P (orig);
ATTR_PERMANENT_P (copy) = ATTR_PERMANENT_P (orig);
ATTR_EQ_ATTR_P (copy) = ATTR_EQ_ATTR_P (orig);
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = attr_copy_rtx (XEXP (orig, i));
break;
case 'E':
case 'V':
XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = attr_copy_rtx (XVECEXP (orig, i, j));
}
break;
case 'n':
case 'i':
XINT (copy, i) = XINT (orig, i);
break;
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
case 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
default:
abort ();
}
}
return copy;
}
rtx
check_attr_test (exp, is_const, lineno)
rtx exp;
int is_const;
int lineno;
{
struct attr_desc *attr;
struct attr_value *av;
const char *name_ptr, *p;
rtx orexp, newexp;
switch (GET_CODE (exp))
{
case EQ_ATTR:
if (XSTR (exp, 1)[0] == '!')
return check_attr_test (attr_rtx (NOT,
attr_eq (XSTR (exp, 0),
&XSTR (exp, 1)[1])),
is_const, lineno);
else if (n_comma_elts (XSTR (exp, 1)) == 1)
{
attr = find_attr (XSTR (exp, 0), 0);
if (attr == NULL)
{
if (! strcmp (XSTR (exp, 0), "alternative"))
{
XSTR (exp, 0) = alternative_name;
ATTR_IND_SIMPLIFIED_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)
ATTR_IND_SIMPLIFIED_P (exp) = 1;
if (attr->is_numeric)
{
for (p = XSTR (exp, 1); *p; p++)
if (! ISDIGIT (*p))
fatal ("attribute `%s' takes only numeric values",
XSTR (exp, 0));
}
else
{
for (av = attr->first_value; av; av = av->next)
if (GET_CODE (av->value) == CONST_STRING
&& ! strcmp (XSTR (exp, 1), XSTR (av->value, 0)))
break;
if (av == NULL)
fatal ("unknown value `%s' for `%s' attribute",
XSTR (exp, 1), XSTR (exp, 0));
}
}
else
{
orexp = false_rtx;
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
newexp = attr_eq (XSTR (exp, 0), p);
orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
}
return check_attr_test (orexp, is_const, lineno);
}
break;
case ATTR_FLAG:
break;
case CONST_INT:
if (XWINT (exp, 0))
return true_rtx;
else
return false_rtx;
case IOR:
case AND:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
XEXP (exp, 1) = check_attr_test (XEXP (exp, 1), is_const, lineno);
break;
case NOT:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
break;
case MATCH_INSN:
case MATCH_OPERAND:
if (is_const)
fatal ("RTL operator \"%s\" not valid in constant attribute test",
GET_RTX_NAME (GET_CODE (exp)));
ATTR_IND_SIMPLIFIED_P (exp) = 1;
break;
case LE: case LT: case GT: case GE:
case LEU: case LTU: case GTU: case GEU:
case NE: case EQ:
if (GET_CODE (XEXP (exp, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (exp, 1)) == SYMBOL_REF)
exp = attr_rtx (GET_CODE (exp),
attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 0), 0)),
attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 1), 0)));
ATTR_IND_SIMPLIFIED_P (exp) = 1;
break;
case SYMBOL_REF:
if (is_const)
{
exp = attr_rtx (SYMBOL_REF, XSTR (exp, 0));
ATTR_IND_SIMPLIFIED_P (exp) = 1;
break;
}
default:
fatal ("RTL operator \"%s\" not valid in attribute test",
GET_RTX_NAME (GET_CODE (exp)));
}
return exp;
}
static rtx
check_attr_value (exp, attr)
rtx exp;
struct attr_desc *attr;
{
struct attr_value *av;
const char *p;
int i;
switch (GET_CODE (exp))
{
case CONST_INT:
if (attr && ! attr->is_numeric)
{
message_with_line (attr->lineno,
"CONST_INT not valid for non-numeric attribute %s",
attr->name);
have_error = 1;
break;
}
if (INTVAL (exp) < 0 && ! attr->negative_ok)
{
message_with_line (attr->lineno,
"negative numeric value specified for attribute %s",
attr->name);
have_error = 1;
break;
}
break;
case CONST_STRING:
if (! strcmp (XSTR (exp, 0), "*"))
break;
if (attr == 0 || attr->is_numeric)
{
p = XSTR (exp, 0);
if (attr && attr->negative_ok && *p == '-')
p++;
for (; *p; p++)
if (! ISDIGIT (*p))
{
message_with_line (attr ? attr->lineno : 0,
"non-numeric value for numeric attribute %s",
attr ? attr->name : "internal");
have_error = 1;
break;
}
break;
}
for (av = attr->first_value; av; av = av->next)
if (GET_CODE (av->value) == CONST_STRING
&& ! strcmp (XSTR (av->value, 0), XSTR (exp, 0)))
break;
if (av == NULL)
{
message_with_line (attr->lineno,
"unknown value `%s' for `%s' attribute",
XSTR (exp, 0), attr ? attr->name : "internal");
have_error = 1;
}
break;
case IF_THEN_ELSE:
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0),
attr ? attr->is_const : 0,
attr ? attr->lineno : 0);
XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
break;
case PLUS:
case MINUS:
case MULT:
case DIV:
case MOD:
if (attr && !attr->is_numeric)
{
message_with_line (attr->lineno,
"invalid operation `%s' for non-numeric attribute value",
GET_RTX_NAME (GET_CODE (exp)));
have_error = 1;
break;
}
case IOR:
case AND:
XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
break;
case FFS:
case CLZ:
case CTZ:
case POPCOUNT:
case PARITY:
XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
break;
case COND:
if (XVECLEN (exp, 0) % 2 != 0)
{
message_with_line (attr->lineno,
"first operand of COND must have even length");
have_error = 1;
break;
}
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i),
attr ? attr->is_const : 0,
attr ? attr->lineno : 0);
XVECEXP (exp, 0, i + 1)
= check_attr_value (XVECEXP (exp, 0, i + 1), attr);
}
XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
break;
case ATTR:
{
struct attr_desc *attr2 = find_attr (XSTR (exp, 0), 0);
if (attr2 == NULL)
{
message_with_line (attr ? attr->lineno : 0,
"unknown attribute `%s' in ATTR",
XSTR (exp, 0));
have_error = 1;
}
else if (attr && attr->is_const && ! attr2->is_const)
{
message_with_line (attr->lineno,
"non-constant attribute `%s' referenced from `%s'",
XSTR (exp, 0), attr->name);
have_error = 1;
}
else if (attr
&& (attr->is_numeric != attr2->is_numeric
|| (! attr->negative_ok && attr2->negative_ok)))
{
message_with_line (attr->lineno,
"numeric attribute mismatch calling `%s' from `%s'",
XSTR (exp, 0), attr->name);
have_error = 1;
}
}
break;
case SYMBOL_REF:
return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
default:
message_with_line (attr ? attr->lineno : 0,
"invalid operation `%s' for attribute value",
GET_RTX_NAME (GET_CODE (exp)));
have_error = 1;
break;
}
return exp;
}
static rtx
convert_set_attr_alternative (exp, id)
rtx exp;
struct insn_def *id;
{
int num_alt = id->num_alternatives;
rtx condexp;
int i;
if (XVECLEN (exp, 1) != num_alt)
{
message_with_line (id->lineno,
"bad number of entries in SET_ATTR_ALTERNATIVE");
have_error = 1;
return NULL_RTX;
}
condexp = rtx_alloc (COND);
XVEC (condexp, 0) = rtvec_alloc ((num_alt - 1) * 2);
for (i = 0; i < num_alt - 1; i++)
{
const char *p;
p = attr_numeral (i);
XVECEXP (condexp, 0, 2 * i) = attr_eq (alternative_name, p);
XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP (exp, 1, i);
}
XEXP (condexp, 1) = XVECEXP (exp, 1, i);
return attr_rtx (SET, attr_rtx (ATTR, XSTR (exp, 0)), condexp);
}
static rtx
convert_set_attr (exp, id)
rtx exp;
struct insn_def *id;
{
rtx newexp;
const char *name_ptr;
char *p;
int n;
n = n_comma_elts (XSTR (exp, 1));
if (n == 1)
return attr_rtx (SET,
attr_rtx (ATTR, XSTR (exp, 0)),
attr_rtx (CONST_STRING, XSTR (exp, 1)));
newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);
XSTR (newexp, 0) = XSTR (exp, 0);
XVEC (newexp, 1) = rtvec_alloc (n);
name_ptr = XSTR (exp, 1);
n = 0;
while ((p = next_comma_elt (&name_ptr)) != NULL)
XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
return convert_set_attr_alternative (newexp, id);
}
static void
check_defs ()
{
struct insn_def *id;
struct attr_desc *attr;
int i;
rtx value;
for (id = defs; id; id = id->next)
{
if (XVEC (id->def, id->vec_idx) == NULL)
continue;
for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
{
value = XVECEXP (id->def, id->vec_idx, i);
switch (GET_CODE (value))
{
case SET:
if (GET_CODE (XEXP (value, 0)) != ATTR)
{
message_with_line (id->lineno, "bad attribute set");
have_error = 1;
value = NULL_RTX;
}
break;
case SET_ATTR_ALTERNATIVE:
value = convert_set_attr_alternative (value, id);
break;
case SET_ATTR:
value = convert_set_attr (value, id);
break;
default:
message_with_line (id->lineno, "invalid attribute code %s",
GET_RTX_NAME (GET_CODE (value)));
have_error = 1;
value = NULL_RTX;
}
if (value == NULL_RTX)
continue;
if ((attr = find_attr (XSTR (XEXP (value, 0), 0), 0)) == NULL)
{
message_with_line (id->lineno, "unknown attribute %s",
XSTR (XEXP (value, 0), 0));
have_error = 1;
continue;
}
XVECEXP (id->def, id->vec_idx, i) = value;
XEXP (value, 1) = check_attr_value (XEXP (value, 1), attr);
}
}
}
#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++)
*p = TOUPPER (*p);
value = attr_rtx (SYMBOL_REF, string);
ATTR_IND_SIMPLIFIED_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 || ATTR_IND_SIMPLIFIED_P (exp))
break;
ATTR_IND_SIMPLIFIED_P (exp) = 1;
#if 0
exp = convert_const_symbol_ref (exp, attr);
ATTR_IND_SIMPLIFIED_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)
return operate_exp (op, left, XEXP (right, 1));
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)
return operate_exp (op, XEXP (left, 1), right);
if (rtx_equal_p (newexp, left))
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, unit->first_lineno);
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, op->lineno);
}
}
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 ***)
xmalloc ((num_units + 1) * sizeof (struct function_unit_op **));
unit_num = (struct function_unit **)
xmalloc ((num_units + 1) * sizeof (struct function_unit *));
unit_num[num_units] = unit = (struct function_unit *)
xmalloc (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 **)
xmalloc (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 **)
xmalloc (unit_num[num_units]->num_opclasses
* sizeof (struct function_unit_op *));
for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next)
memcpy (&op_array[i], unit_ops[unit->num],
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)
{
rtx blockage = op->issue_exp;
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;
{
int i;
int j;
enum rtx_code code;
const 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 CONST_VECTOR:
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) PARAMS ((rtx));
rtx (*address_fn) PARAMS ((rtx));
{
int i;
rtx newexp;
if (GET_CODE (exp) == COND)
{
address_used = 0;
for (i = 0; i < XVECLEN (exp, 0); i += 2)
walk_attr_value (XVECEXP (exp, 0, i));
if (address_used)
return (*address_fn) (exp);
newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
XVECEXP (newexp, 0, i + 1)
= substitute_address (XVECEXP (exp, 0, i + 1),
no_address_fn, address_fn);
}
XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
no_address_fn, address_fn);
return newexp;
}
else if (GET_CODE (exp) == IF_THEN_ELSE)
{
address_used = 0;
walk_attr_value (XEXP (exp, 0));
if (address_used)
return (*address_fn) (exp);
return attr_rtx (IF_THEN_ELSE,
substitute_address (XEXP (exp, 0),
no_address_fn, address_fn),
substitute_address (XEXP (exp, 1),
no_address_fn, address_fn),
substitute_address (XEXP (exp, 2),
no_address_fn, address_fn));
}
return (*no_address_fn) (exp);
}
static void
make_length_attrs ()
{
static const char *const new_names[] = {"*insn_default_length",
"*insn_variable_length_p",
"*insn_current_length"};
static rtx (*const no_address_fn[]) PARAMS ((rtx)) = {identity_fn, zero_fn, zero_fn};
static rtx (*const address_fn[]) PARAMS ((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 < ARRAY_SIZE (new_names); i++)
{
make_internal_attr (new_names[i],
substitute_address (length_attr->default_val->value,
no_address_fn[i], address_fn[i]),
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);
rtx *tests = (rtx *) xmalloc (len * sizeof (rtx));
int allsame = 1;
rtx ret;
obstack_finish (rtl_obstack);
memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
if (GET_CODE (defval) == COND)
new_defval = simplify_cond (defval, insn_code, insn_index);
for (i = 0; i < len; i += 2)
{
rtx newtest, newval;
newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
tests[i] = newtest;
newval = tests[i + 1];
if (GET_CODE (newval) == COND)
newval = simplify_cond (newval, insn_code, insn_index);
if (newtest == true_rtx)
{
len = i;
defval = tests[i + 1];
new_defval = newval;
}
else if (newtest == false_rtx)
{
for (j = i; j < len - 2; j++)
tests[j] = tests[j + 2];
len -= 2;
}
else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
{
tests[i - 2]
= insert_right_side (IOR, tests[i - 2], newtest,
insn_code, insn_index);
for (j = i; j < len - 2; j++)
tests[j] = tests[j + 2];
len -= 2;
}
else
tests[i + 1] = newval;
}
while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
len -= 2;
if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1))
allsame = 0;
else
for (i = 0; i < len; i++)
if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
{
allsame = 0;
break;
}
if (len == 0)
{
if (GET_CODE (defval) == COND)
ret = simplify_cond (defval, insn_code, insn_index);
else
ret = defval;
}
else if (allsame)
ret = exp;
else
{
rtx newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (len);
memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx));
XEXP (newexp, 1) = new_defval;
ret = newexp;
}
free (tests);
return ret;
}
static void
remove_insn_ent (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_in_temp (newexp, insn_code, insn_index);
}
static int
compute_alternative_mask (exp, code)
rtx exp;
enum rtx_code code;
{
const char *string;
if (GET_CODE (exp) == code)
return compute_alternative_mask (XEXP (exp, 0), code)
| compute_alternative_mask (XEXP (exp, 1), code);
else if (code == AND && GET_CODE (exp) == NOT
&& GET_CODE (XEXP (exp, 0)) == EQ_ATTR
&& XSTR (XEXP (exp, 0), 0) == alternative_name)
string = XSTR (XEXP (exp, 0), 1);
else if (code == IOR && GET_CODE (exp) == EQ_ATTR
&& XSTR (exp, 0) == alternative_name)
string = XSTR (exp, 1);
else
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));
ATTR_IND_SIMPLIFIED_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;
char string[256];
if (GET_CODE (exp) != EQ_ATTR)
abort ();
if (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2 > 256)
abort ();
strcpy (string, XSTR (exp, 0));
strcat (string, "_");
strcat (string, XSTR (exp, 1));
for (p = string; *p; p++)
*p = TOUPPER (*p);
newexp = attr_rtx (EQ, value,
attr_rtx (SYMBOL_REF,
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_in_temp (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 (! ATTR_IND_SIMPLIFIED_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_in_temp (newexp, insn_code, insn_index);
}
}
else if (GET_CODE (exp) == IOR)
{
temp = *pterm;
left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
left_eliminates_term = (temp == true_rtx);
temp = *pterm;
right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
right_eliminates_term = (temp == true_rtx);
if (left_eliminates_term && right_eliminates_term)
*pterm = true_rtx;
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
newexp = attr_rtx (GET_CODE (exp), left, right);
exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
}
if (exp == *pterm)
return true_rtx;
else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm)
return false_rtx;
else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0))
return false_rtx;
else if (GET_CODE (exp) == EQ_ATTR && 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_in_temp (newexp, insn_code, insn_index);
}
}
else if (GET_CODE (exp) == AND)
{
temp = *pterm;
left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
left_eliminates_term = (temp == false_rtx);
temp = *pterm;
right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
right_eliminates_term = (temp == false_rtx);
if (left_eliminates_term && right_eliminates_term)
*pterm = false_rtx;
if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
{
newexp = attr_rtx (GET_CODE (exp), left, right);
exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
}
}
if (attr_equal_p (exp, *pterm))
return false_rtx;
else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm))
return true_rtx;
else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp))
return true_rtx;
else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
&& GET_CODE (XEXP (exp, 0)) == EQ_ATTR
&& XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0))
*pterm = false_rtx;
else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
&& GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR
&& XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0))
return false_rtx;
return exp;
}
static int
attr_rtx_cost (x)
rtx x;
{
int cost = 0;
enum rtx_code code;
if (!x)
return 0;
code = GET_CODE (x);
switch (code)
{
case MATCH_OPERAND:
if (XSTR (x, 1)[0])
return 10;
else
return 0;
case EQ_ATTR:
if (!strcmp (XSTR (x, 0), "alternative"))
return 0;
else
return 5;
default:
{
int i, j;
const char *fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'V':
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
cost += attr_rtx_cost (XVECEXP (x, i, j));
break;
case 'e':
cost += attr_rtx_cost (XEXP (x, i));
break;
}
}
}
break;
}
return cost;
}
static rtx
simplify_test_exp_in_temp (exp, insn_code, insn_index)
rtx exp;
int insn_code, insn_index;
{
rtx x;
struct obstack *old;
if (ATTR_IND_SIMPLIFIED_P (exp))
return exp;
old = rtl_obstack;
rtl_obstack = temp_obstack;
x = simplify_test_exp (exp, insn_code, insn_index);
rtl_obstack = old;
if (x == exp || rtl_obstack == temp_obstack)
return x;
return attr_copy_rtx (x);
}
static 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;
if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp))
return exp;
switch (GET_CODE (exp))
{
case AND:
left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (left);
if (left == false_rtx)
return false_rtx;
right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (right);
if (left == false_rtx)
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)
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)
return true_rtx;
right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
SIMPLIFY_ALTERNATIVE (right);
if (right == true_rtx)
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)
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)
return true_rtx;
else if (left == true_rtx)
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)
{
rtx x;
x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
if (attr_rtx_cost(x) < 20)
return x;
}
break;
default:
break;
}
if (insn_code != -2
&& ! ATTR_IND_SIMPLIFIED_P (newexp))
return copy_rtx_unchanging (newexp);
return newexp;
}
static void
optimize_attrs ()
{
struct attr_desc *attr;
struct attr_value *av;
struct insn_ent *ie;
rtx newexp;
int i;
struct attr_value_list
{
struct attr_value *av;
struct insn_ent *ie;
struct attr_desc *attr;
struct attr_value_list *next;
};
struct attr_value_list **insn_code_values;
struct attr_value_list *ivbuf;
struct attr_value_list *iv;
if (num_insn_ents == 0)
return;
insn_code_values
= (struct attr_value_list **) xmalloc ((insn_code_number + 2)
* sizeof (struct attr_value_list *));
memset ((char *) insn_code_values, 0,
(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);
for (iv = insn_code_values[i]; iv; iv = iv->next)
{
struct obstack *old = rtl_obstack;
attr = iv->attr;
av = iv->av;
ie = iv->ie;
if (GET_CODE (av->value) != COND)
continue;
rtl_obstack = temp_obstack;
#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 = av->value;
while (GET_CODE (newexp) == COND)
{
rtx newexp2 = simplify_cond (newexp, ie->insn_code,
ie->insn_index);
if (newexp2 == newexp)
break;
newexp = newexp2;
}
rtl_obstack = old;
if (newexp != av->value)
{
newexp = attr_copy_rtx (newexp);
remove_insn_ent (av, ie);
av = get_attr_value (newexp, attr, ie->insn_code);
iv->av = av;
insert_insn_ent (av, ie);
}
}
}
free (ivbuf);
free (insn_code_values - 2);
}
#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;
rtx ret;
if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0)
{
unmark_used_attributes (list, 0, 0);
return exp;
}
space = (struct dimension *) xmalloc (ndim * sizeof (struct dimension));
total = 1;
for (ndim = 0; list; ndim++)
{
const 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 *) xmalloc (total * sizeof (rtx));
condval = (rtx *) xmalloc (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);
free (space);
most_tests = -1;
for (i = num_marks = 0; i < total; i++)
if (GET_CODE (condval[i]) == CONST_STRING
&& ! ATTR_EQ_ATTR_P (condval[i]))
{
ATTR_EQ_ATTR_P (condval[i]) = 1;
for (j = new_marks = 0; j < total; j++)
if (GET_CODE (condval[j]) == CONST_STRING
&& ATTR_EQ_ATTR_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++)
ATTR_EQ_ATTR_P (condval[i]) = 0;
if (num_marks == 0)
ret = exp;
else if (total == most_tests)
ret = defval;
else
{
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++;
}
ret = condexp;
}
free (condtest);
free (condval);
return ret;
}
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 (! ATTR_EQ_ATTR_P (exp))
{
rtx link = rtx_alloc (EXPR_LIST);
XEXP (link, 0) = exp;
XEXP (link, 1) = *terms;
*terms = link;
*nterms += 1;
ATTR_EQ_ATTR_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)
ATTR_EQ_ATTR_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 (ATTR_EQ_ATTR_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)
ATTR_EQ_ATTR_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)
ATTR_EQ_ATTR_P (x) = 1;
}
return exp;
}
static rtx
simplify_with_current_value_aux (exp)
rtx exp;
{
int i;
rtx cond;
switch (GET_CODE (exp))
{
case EQ_ATTR:
if (ATTR_EQ_ATTR_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;
{
int i;
int j;
enum rtx_code code;
const char *fmt;
ATTR_CURR_SIMPLIFIED_P (x) = 0;
if (ATTR_IND_SIMPLIFIED_P (x))
return;
code = GET_CODE (x);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case EQ_ATTR:
case ATTR_FLAG:
return;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'V':
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
clear_struct_flag (XVECEXP (x, i, j));
break;
case 'e':
clear_struct_flag (XEXP (x, i));
break;
}
}
}
static int
count_sub_rtxs (x, max)
rtx x;
int max;
{
int i;
int j;
enum rtx_code code;
const char *fmt;
int total = 0;
code = GET_CODE (x);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case EQ_ATTR:
case ATTR_FLAG:
return 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, lineno)
rtx exp;
int lineno;
{
struct attr_desc *attr;
struct attr_value *av;
const char *name_ptr;
char *p;
attr = find_attr (XSTR (exp, 0), 1);
if (attr->default_val)
{
message_with_line (lineno, "duplicate definition for attribute %s",
attr->name);
message_with_line (attr->lineno, "previous definition");
have_error = 1;
return;
}
attr->lineno = lineno;
if (*XSTR (exp, 1) == '\0')
attr->is_numeric = 1;
else
{
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
{
av = (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)
{
message_with_line (lineno,
"constant attributes may not take numeric values");
have_error = 1;
}
XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
}
if (! strcmp (attr->name, "length") && ! attr->is_numeric)
{
message_with_line (lineno,
"`length' attribute must take numeric values");
have_error = 1;
}
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
}
static int
count_alternatives (exp)
rtx exp;
{
int i, j, n;
const char *fmt;
if (GET_CODE (exp) == MATCH_OPERAND)
return n_comma_elts (XSTR (exp, 2));
for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
switch (*fmt++)
{
case 'e':
case 'u':
n = count_alternatives (XEXP (exp, i));
if (n)
return n;
break;
case 'E':
case 'V':
if (XVEC (exp, i) != NULL)
for (j = 0; j < XVECLEN (exp, i); j++)
{
n = count_alternatives (XVECEXP (exp, i, j));
if (n)
return n;
}
}
return 0;
}
static int
compares_alternatives_p (exp)
rtx exp;
{
int i, j;
const char *fmt;
if (GET_CODE (exp) == EQ_ATTR && XSTR (exp, 0) == alternative_name)
return 1;
for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
switch (*fmt++)
{
case 'e':
case 'u':
if (compares_alternatives_p (XEXP (exp, i)))
return 1;
break;
case 'E':
for (j = 0; j < XVECLEN (exp, i); j++)
if (compares_alternatives_p (XVECEXP (exp, i, j)))
return 1;
break;
}
return 0;
}
static int
contained_in_p (inner, exp)
rtx inner;
rtx exp;
{
int i, j;
const char *fmt;
if (rtx_equal_p (inner, exp))
return 1;
for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
switch (*fmt++)
{
case 'e':
case 'u':
if (contained_in_p (inner, XEXP (exp, i)))
return 1;
break;
case 'E':
for (j = 0; j < XVECLEN (exp, i); j++)
if (contained_in_p (inner, XVECEXP (exp, i, j)))
return 1;
break;
}
return 0;
}
static void
gen_insn (exp, lineno)
rtx exp;
int lineno;
{
struct insn_def *id;
id = (struct insn_def *) oballoc (sizeof (struct insn_def));
id->next = defs;
defs = id;
id->def = exp;
id->lineno = lineno;
switch (GET_CODE (exp))
{
case DEFINE_INSN:
id->insn_code = insn_code_number;
id->insn_index = insn_index_number;
id->num_alternatives = count_alternatives (exp);
if (id->num_alternatives == 0)
id->num_alternatives = 1;
id->vec_idx = 4;
break;
case DEFINE_PEEPHOLE:
id->insn_code = insn_code_number;
id->insn_index = insn_index_number;
id->num_alternatives = count_alternatives (exp);
if (id->num_alternatives == 0)
id->num_alternatives = 1;
id->vec_idx = 3;
break;
case DEFINE_ASM_ATTRIBUTES:
id->insn_code = -1;
id->insn_index = -1;
id->num_alternatives = 1;
id->vec_idx = 0;
got_define_asm_attributes = 1;
break;
default:
abort ();
}
}
static void
gen_delay (def, lineno)
rtx def;
int lineno;
{
struct delay_desc *delay;
int i;
if (XVECLEN (def, 1) % 3 != 0)
{
message_with_line (lineno,
"number of elements in DEFINE_DELAY must be multiple of three");
have_error = 1;
return;
}
for (i = 0; i < XVECLEN (def, 1); i += 3)
{
if (XVECEXP (def, 1, i + 1))
have_annul_true = 1;
if (XVECEXP (def, 1, i + 2))
have_annul_false = 1;
}
delay = (struct delay_desc *) oballoc (sizeof (struct delay_desc));
delay->def = def;
delay->num = ++num_delays;
delay->next = delays;
delay->lineno = lineno;
delays = delay;
}
static void
gen_unit (def, lineno)
rtx def;
int lineno;
{
struct function_unit *unit;
struct function_unit_op *op;
const 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)
{
message_with_line (lineno,
"differing specifications given for function unit %s",
unit->name);
message_with_line (unit->first_lineno, "previous definition");
have_error = 1;
return;
}
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;
unit->first_lineno = lineno;
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;
op->lineno = lineno;
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_SET_P () ? INSN_ADDRESSES (INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])) : 0",
XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
case PC:
printf ("insn_current_reference_address (insn)");
break;
case CONST_STRING:
printf ("%s", XSTR (exp, 0));
break;
case IF_THEN_ELSE:
write_test_expr (XEXP (exp, 0), flags & 2);
printf (" ? ");
write_test_expr (XEXP (exp, 1), flags | 1);
printf (" : ");
write_test_expr (XEXP (exp, 2), flags | 1);
break;
default:
fatal ("bad RTX code `%s' in attribute calculation\n",
GET_RTX_NAME (code));
}
printf (")");
}
static int
max_attr_value (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;
{
int i, j;
const char *fmt;
RTX_CODE code;
if (exp == NULL)
return;
code = GET_CODE (exp);
switch (code)
{
case SYMBOL_REF:
if (! ATTR_IND_SIMPLIFIED_P (exp))
must_extract = must_constrain = 1;
return;
case MATCH_OPERAND:
must_extract = 1;
return;
case EQ_ATTR:
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 ("extern enum attr_%s ", attr->name);
else if (attr->unsigned_p)
printf ("extern unsigned int ");
else
printf ("extern int ");
if (attr->name[0] == '*')
printf ("%s PARAMS ((rtx));\n", &attr->name[1]);
else
printf ("get_attr_%s PARAMS ((%s));\n", attr->name,
(attr->is_const ? "void" : "rtx"));
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 ATTRIBUTE_UNUSED;\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_constrain)
{
write_indent (indent + 2);
printf ("extract_constrain_insn_cached (insn);\n");
}
else if (must_extract)
{
write_indent (indent + 2);
printf ("extract_insn_cached (insn);\n");
}
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;
{
const char *fmt;
int i, ie, j, je;
if (GET_CODE (p) == EQ_ATTR)
{
if (XSTR (p, 0) != attr->name)
return 0;
if (!attr->is_numeric)
printf (" enum attr_%s ", attr->name);
else if (attr->unsigned_p)
printf (" unsigned int ");
else
printf (" int ");
printf ("attr_%s = get_attr_%s (insn);\n", attr->name, attr->name);
return 1;
}
fmt = GET_RTX_FORMAT (GET_CODE (p));
ie = GET_RTX_LENGTH (GET_CODE (p));
for (i = 0; i < ie; i++)
{
switch (*fmt++)
{
case 'e':
if (write_expr_attr_cache (XEXP (p, i), attr))
return 1;
break;
case 'E':
je = XVECLEN (p, i);
for (j = 0; j < je; ++j)
if (write_expr_attr_cache (XVECEXP (p, i, j), attr))
return 1;
break;
}
}
return 0;
}
static void
write_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 (" 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;
const 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 CONST_INT:
printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (value));
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)
const char *str;
{
while (*str)
{
putchar (TOUPPER(*str));
str++;
}
}
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 ATTRIBUTE_UNUSED;\n");
printf (" int slot;\n");
printf (" rtx candidate_insn;\n");
printf (" int flags ATTRIBUTE_UNUSED;\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 ("const 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");
}
if (num_units == 0)
printf ("{\"dummy\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* a dummy element */");
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[256];
int using_case;
int i;
printf ("static int %s_unit_%s PARAMS ((rtx, rtx));\n", unit->name, name);
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");
if (strlen (unit->name) + sizeof "*_cases" > 256)
abort ();
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 char *
next_comma_elt (pstr)
const char **pstr;
{
const char *start;
start = scan_comma_elt (pstr);
if (start == NULL)
return NULL;
return attr_string (start, *pstr - start);
}
static struct attr_desc *
find_attr (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->unsigned_p = attr->func_units_p = attr->blockage_p = 0;
attr->next = attrs[index];
attrs[index] = attr;
return attr;
}
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;
}
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;
}
static rtx
copy_rtx_unchanging (orig)
rtx orig;
{
#if 0
rtx copy;
RTX_CODE code;
#endif
if (ATTR_IND_SIMPLIFIED_P (orig) || ATTR_CURR_SIMPLIFIED_P (orig))
return orig;
ATTR_CURR_SIMPLIFIED_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));
ATTR_IND_SIMPLIFIED_P (copy) = 1;
memcpy (&XEXP (copy, 0), &XEXP (orig, 0),
GET_RTX_LENGTH (GET_CODE (copy)) * sizeof (rtx));
return copy;
#endif
}
static 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");
}
}
extern int main PARAMS ((int, char **));
int
main (argc, argv)
int argc;
char **argv;
{
rtx desc;
struct attr_desc *attr;
struct insn_def *id;
rtx tem;
int i;
progname = "genattrtab";
if (argc <= 1)
fatal ("no input file name");
if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
return (FATAL_EXIT_CODE);
obstack_init (hash_obstack);
obstack_init (temp_obstack);
true_rtx = rtx_alloc (CONST_INT);
XWINT (true_rtx, 0) = 1;
false_rtx = rtx_alloc (CONST_INT);
XWINT (false_rtx, 0) = 0;
ATTR_IND_SIMPLIFIED_P (true_rtx) = ATTR_IND_SIMPLIFIED_P (false_rtx) = 1;
ATTR_PERMANENT_P (true_rtx) = ATTR_PERMANENT_P (false_rtx) = 1;
alternative_name = attr_string ("alternative", strlen ("alternative"));
printf ("/* Generated automatically by the program `genattrtab'\n\
from the machine description file `md'. */\n\n");
initiate_automaton_gen (argc, argv);
while (1)
{
int lineno;
desc = read_md_rtx (&lineno, &insn_code_number);
if (desc == NULL)
break;
switch (GET_CODE (desc))
{
case DEFINE_INSN:
case DEFINE_PEEPHOLE:
case DEFINE_ASM_ATTRIBUTES:
gen_insn (desc, lineno);
break;
case DEFINE_ATTR:
gen_attr (desc, lineno);
break;
case DEFINE_DELAY:
gen_delay (desc, lineno);
break;
case DEFINE_FUNCTION_UNIT:
gen_unit (desc, lineno);
break;
case DEFINE_CPU_UNIT:
gen_cpu_unit (desc);
break;
case DEFINE_QUERY_CPU_UNIT:
gen_query_cpu_unit (desc);
break;
case DEFINE_BYPASS:
gen_bypass (desc);
break;
case EXCLUSION_SET:
gen_excl_set (desc);
break;
case PRESENCE_SET:
gen_presence_set (desc);
break;
case FINAL_PRESENCE_SET:
gen_final_presence_set (desc);
break;
case ABSENCE_SET:
gen_absence_set (desc);
break;
case FINAL_ABSENCE_SET:
gen_final_absence_set (desc);
break;
case DEFINE_AUTOMATON:
gen_automaton (desc);
break;
case AUTOMATA_OPTION:
gen_automata_option (desc);
break;
case DEFINE_RESERVATION:
gen_reserv (desc);
break;
case DEFINE_INSN_RESERVATION:
gen_insn_reserv (desc);
break;
default:
break;
}
if (GET_CODE (desc) != DEFINE_ASM_ATTRIBUTES)
insn_index_number++;
}
if (have_error)
return FATAL_EXIT_CODE;
insn_code_number++;
if (! got_define_asm_attributes)
{
tem = rtx_alloc (DEFINE_ASM_ATTRIBUTES);
XVEC (tem, 0) = rtvec_alloc (0);
gen_insn (tem, 0);
}
if (num_delays)
expand_delays ();
if (num_units || num_dfa_decls)
{
expand_units ();
expand_automata ();
}
printf ("#include \"config.h\"\n");
printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"tm_p.h\"\n");
printf ("#include \"insn-config.h\"\n");
printf ("#include \"recog.h\"\n");
printf ("#include \"regs.h\"\n");
printf ("#include \"real.h\"\n");
printf ("#include \"output.h\"\n");
printf ("#include \"insn-attr.h\"\n");
printf ("#include \"toplev.h\"\n");
printf ("#include \"flags.h\"\n");
printf ("#include \"function.h\"\n");
printf ("\n");
printf ("#define operands recog_data.operand\n\n");
insn_alternatives = (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);
if (have_error)
return FATAL_EXIT_CODE;
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
fill_attr (attr);
make_length_attrs ();
optimize_attrs ();
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
{
if (! attr->is_special && ! attr->is_const)
{
int insn_alts_p;
insn_alts_p
= (attr->name [0] == '*'
&& strcmp (&attr->name [1], INSN_ALTS_FUNC_NAME) == 0);
if (insn_alts_p)
printf ("\n#if AUTOMATON_ALTS\n");
write_attr_get (attr);
if (insn_alts_p)
printf ("#endif\n\n");
}
}
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 || num_dfa_decls)
{
write_function_unit_info ();
write_automata ();
}
write_const_num_delay_slots ();
write_length_unit_log ();
fflush (stdout);
return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
}
const char *
get_insn_name (code)
int code ATTRIBUTE_UNUSED;
{
return NULL;
}