If the attribute `alternative', or a random C expression is present,
`constrain_operands' is called. If either of these cases of a reference to
- an operand is found, `insn_extract' is called.
+ an operand is found, `extract_insn' is called.
The special attribute `length' is also recognized. For this operand,
expressions involving the address of an operand or the current insn,
#include "hconfig.h"
-/* varargs must always be included after *config.h. */
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-#include <stdio.h>
+#include "system.h"
#include "rtl.h"
#include "insn-config.h" /* For REGISTER_CONSTRAINTS */
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-#endif
-#endif
-
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
/* We must include obstack.h after <sys/time.h>, to avoid lossage with
/usr/include/sys/stdtypes.h on Sun OS 4.x. */
#include "obstack.h"
/* Define this so we can link with print-rtl.o to get debug_rtx function. */
char **insn_name_ptr = 0;
-extern void free ();
-extern rtx read_rtx ();
-
-static void fatal ();
-void fancy_abort ();
+static void fatal PVPROTO ((char *, ...))
+ ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
+void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
/* enough space to reserve for printing out ints */
#define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
{
char *name; /* Name of attribute. */
struct attr_desc *next; /* Next attribute. */
- int is_numeric; /* Values of this attribute are numeric. */
- int negative_ok; /* Allow negative numeric values. */
- int unsigned_p; /* Make the output function unsigned int. */
- int is_const; /* Attribute value constant for each run. */
- int is_special; /* Don't call `write_attr_set'. */
+ unsigned is_numeric : 1; /* Values of this attribute are numeric. */
+ unsigned negative_ok : 1; /* Allow negative numeric values. */
+ unsigned unsigned_p : 1; /* Make the output function unsigned int. */
+ unsigned is_const : 1; /* Attribute value constant for each run. */
+ unsigned is_special : 1; /* Don't call `write_attr_set'. */
+ unsigned func_units_p : 1; /* this is the function_units attribute */
+ unsigned blockage_p : 1; /* this is the blockage range function */
struct attr_value *first_value; /* First value of this attribute. */
struct attr_value *default_val; /* Default value for this attribute. */
};
int reload_completed = 0;
-/* Similarly since PRESERVE_DEATH_INFO_REGNO_P might reference "optimize". */
+/* Some machines test `optimize' in macros called from rtlanal.c, so we need
+ to define it here. */
+
int optimize = 0;
/* Simplify an expression. Only call the routine if there is something to
They won't actually be used. */
struct _global_rtl global_rtl;
+rtx pic_offset_table_rtx;
+static void attr_hash_add_rtx PROTO((int, rtx));
+static void attr_hash_add_string PROTO((int, char *));
static rtx attr_rtx PVPROTO((enum rtx_code, ...));
-#ifdef HAVE_VPRINTF
static char *attr_printf PVPROTO((int, char *, ...));
-#else
-static char *attr_printf ();
-#endif
-
static char *attr_string PROTO((char *, int));
static rtx check_attr_test PROTO((rtx, int));
static rtx check_attr_value PROTO((rtx, struct attr_desc *));
-static rtx convert_set_attr_alternative PROTO((rtx, int, int, int));
-static rtx convert_set_attr PROTO((rtx, int, int, int));
+static rtx convert_set_attr_alternative PROTO((rtx, int, int));
+static rtx convert_set_attr PROTO((rtx, int, int));
static void check_defs PROTO((void));
#if 0
static rtx convert_const_symbol_ref PROTO((rtx, struct attr_desc *));
static rtx zero_fn PROTO((rtx));
static rtx one_fn PROTO((rtx));
static rtx max_fn PROTO((rtx));
+static void write_length_unit_log PROTO ((void));
static rtx simplify_cond PROTO((rtx, int, int));
#if 0
static rtx simplify_by_alternatives PROTO((rtx, int, int));
static void gen_unit PROTO((rtx));
static void write_test_expr PROTO((rtx, int));
static int max_attr_value PROTO((rtx));
+static int or_attr_value PROTO((rtx));
static void walk_attr_value PROTO((rtx));
static void write_attr_get PROTO((struct attr_desc *));
static rtx eliminate_known_true PROTO((rtx, rtx, int, int));
char *, rtx, int, int));
static void write_attr_case PROTO((struct attr_desc *, struct attr_value *,
int, char *, char *, int, rtx));
+static void write_unit_name PROTO((char *, int, char *));
static void write_attr_valueq PROTO((struct attr_desc *, char *));
static void write_attr_value PROTO((struct attr_desc *, rtx));
static void write_upcase PROTO((char *));
rtx attr_printf (len, format, [arg1, ..., argn]) */
-#ifdef HAVE_VPRINTF
-
/*VARARGS2*/
static char *
attr_printf VPROTO((register int len, char *fmt, ...))
return attr_string (str, strlen (str));
}
-#else /* not HAVE_VPRINTF */
-
-static char *
-attr_printf (len, fmt, arg1, arg2, arg3)
- int len;
- char *fmt;
- char *arg1, *arg2, *arg3; /* also int */
-{
- register char *str;
-
- /* Print the string into a temporary location. */
- str = (char *) alloca (len);
- sprintf (str, fmt, arg1, arg2, arg3);
-
- return attr_string (str, strlen (str));
-}
-#endif /* not HAVE_VPRINTF */
-
rtx
attr_eq (name, value)
char *name, *value;
return exp;
}
else
- fatal ("Unknown attribute `%s' in EQ_ATTR", XEXP (exp, 0));
+ 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",
- XEXP (exp, 0));
+ XSTR (exp, 0));
/* Copy this just to make it permanent,
so expressions using it can be permanent too. */
for (p = XSTR (exp, 1); *p; p++)
if (*p < '0' || *p > '9')
fatal ("Attribute `%s' takes only numeric values",
- XEXP (exp, 0));
+ XSTR (exp, 0));
}
else
{
if (av == NULL)
fatal ("Unknown value `%s' for `%s' attribute",
- XEXP (exp, 1), XEXP (exp, 0));
+ XSTR (exp, 1), XSTR (exp, 0));
}
}
else
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const);
break;
+ case MATCH_INSN:
case MATCH_OPERAND:
if (is_const)
fatal ("RTL operator \"%s\" not valid in constant attribute test",
- GET_RTX_NAME (MATCH_OPERAND));
+ GET_RTX_NAME (GET_CODE (exp)));
/* These cases can't be simplified. */
RTX_UNCHANGING_P (exp) = 1;
break;
It becomes a COND with each test being (eq_attr "alternative "n") */
static rtx
-convert_set_attr_alternative (exp, num_alt, insn_code, insn_index)
+convert_set_attr_alternative (exp, num_alt, insn_index)
rtx exp;
int num_alt;
- int insn_code, insn_index;
+ int insn_index;
{
rtx condexp;
int i;
list of values is given, convert to SET_ATTR_ALTERNATIVE first. */
static rtx
-convert_set_attr (exp, num_alt, insn_code, insn_index)
+convert_set_attr (exp, num_alt, insn_index)
rtx exp;
int num_alt;
- int insn_code, insn_index;
+ int insn_index;
{
rtx newexp;
char *name_ptr;
while ((p = next_comma_elt (&name_ptr)) != NULL)
XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
- return convert_set_attr_alternative (newexp, num_alt, insn_code, insn_index);
+ return convert_set_attr_alternative (newexp, num_alt, insn_index);
}
\f
/* Scan all definitions, checking for validity. Also, convert any SET_ATTR
case SET_ATTR_ALTERNATIVE:
value = convert_set_attr_alternative (value,
id->num_alternatives,
- id->insn_code,
id->insn_index);
break;
case SET_ATTR:
value = convert_set_attr (value, id->num_alternatives,
- id->insn_code, id->insn_index);
+ id->insn_index);
break;
default:
unitsmask = attr_rtx (FFS, unitsmask);
}
- make_internal_attr ("*function_units_used", unitsmask, 2);
+ make_internal_attr ("*function_units_used", unitsmask, 10);
/* Create an array of ops for each unit. Add an extra unit for the
result_ready_cost function that has the ops of all other units. */
if (unit->needs_range_function)
{
/* Compute the blockage range function and make an attribute
- for writing it's value. */
+ for writing its value. */
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, 4);
+ make_internal_attr (str, newexp, 20);
}
str = attr_printf (strlen (unit->name) + sizeof ("*_unit_ready_cost"),
"*insn_current_length"};
static rtx (*no_address_fn[]) PROTO((rtx)) = {identity_fn, zero_fn, zero_fn};
static rtx (*address_fn[]) PROTO((rtx)) = {max_fn, one_fn, identity_fn};
- int i;
+ size_t i;
struct attr_desc *length_attr, *new_attr;
struct attr_value *av, *new_av;
struct insn_ent *ie, *new_ie;
static rtx
zero_fn (exp)
- rtx exp;
+ rtx exp ATTRIBUTE_UNUSED;
{
return make_numeric_value (0);
}
static rtx
one_fn (exp)
- rtx exp;
+ rtx exp ATTRIBUTE_UNUSED;
{
return make_numeric_value (1);
}
{
return make_numeric_value (max_attr_value (exp));
}
+
+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;
+
+ if (length_attr == 0)
+ return;
+ length_or = or_attr_value (length_attr->default_val->value);
+ 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);
+ 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);
+}
\f
/* Take a COND expression and see if any of the conditions in it can be
simplified. If any are known true or known false for the particular insn
simplify_by_exploding (exp)
rtx exp;
{
- rtx list = 0, link, condexp, defval;
+ rtx list = 0, link, condexp, defval = NULL_RTX;
struct dimension *space;
rtx *condtest, *condval;
int i, j, total, ndim = 0;
}
/* Return the number of RTX objects making up the expression X.
- But if we count more more than MAX objects, stop counting. */
+ But if we count more than MAX objects, stop counting. */
static int
count_sub_rtxs (x, max)
unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2);
}
\f
-/* Given a piece of RTX, print a C expression to test it's truth value.
-
+/* Given a piece of RTX, print a C expression to test its truth value.
We use AND and IOR both for logical and bit-wise operations, so
interpret them as logical unless they are inside a comparison expression.
The first bit of FLAGS will be non-zero in that case.
XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
break;
+ case MATCH_INSN:
+ printf ("%s (insn)", XSTR (exp, 0));
+ break;
+
/* Constant integer. */
case CONST_INT:
printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
- /* The address of the current insn. It would be more consistent with
- other usage to make this the address of the NEXT insn, but this gets
- too confusing because of the ambiguity regarding the length of the
- current insn. */
case PC:
- printf ("insn_current_address");
+ /* The address of the current insn. We implement this actually as the
+ address of the current insn for backward branches, but the last
+ address of the next insn for forward branches, and both with
+ adjustments that account for the worst-case possible stretching of
+ intervening alignments between this insn and its destination. */
+ printf("insn_current_reference_address (insn)");
break;
case CONST_STRING:
return current_max;
}
+
+/* Given an attribute value, return the result of ORing together all
+ CONST_STRING arguments encountered. It is assumed that they are
+ all numeric. */
+
+static int
+or_attr_value (exp)
+ rtx exp;
+{
+ int current_or = 0;
+ int i;
+
+ if (GET_CODE (exp) == CONST_STRING)
+ return atoi (XSTR (exp, 0));
+
+ else if (GET_CODE (exp) == COND)
+ {
+ for (i = 0; i < XVECLEN (exp, 0); i += 2)
+ {
+ current_or |= or_attr_value (XVECEXP (exp, 0, i + 1));
+ }
+
+ current_or |= or_attr_value (XEXP (exp, 1));
+ }
+
+ else if (GET_CODE (exp) == IF_THEN_ELSE)
+ {
+ current_or = or_attr_value (XEXP (exp, 1));
+ current_or |= or_attr_value (XEXP (exp, 2));
+ }
+
+ else
+ abort ();
+
+ return current_or;
+}
\f
/* Scan an attribute value, possibly a conditional, and record what actions
will be required to do any conditional tests in it.
if (must_extract)
{
write_indent (indent + 2);
- printf ("insn_extract (insn);\n");
+ printf ("extract_insn (insn);\n");
}
if (must_constrain)
{
#ifdef REGISTER_CONSTRAINTS
write_indent (indent + 2);
- printf ("if (! constrain_operands (INSN_CODE (insn), reload_completed))\n");
+ printf ("if (! constrain_operands (reload_completed))\n");
write_indent (indent + 2);
printf (" fatal_insn_not_found (insn);\n");
#endif
/* Utilities to write names in various forms. */
static void
+write_unit_name (prefix, num, suffix)
+ char *prefix;
+ int num;
+ char *suffix;
+{
+ struct function_unit *unit;
+
+ for (unit = units; unit; unit = unit->next)
+ if (unit->num == num)
+ {
+ printf ("%s%s%s", prefix, unit->name, suffix);
+ return;
+ }
+
+ printf ("%s<unknown>%s", prefix, suffix);
+}
+
+static void
write_attr_valueq (attr, s)
struct attr_desc *attr;
char *s;
{
if (attr->is_numeric)
{
- printf ("%s", s);
- /* Make the blockage range values easier to read. */
- if (strlen (s) > 1)
- printf (" /* 0x%x */", atoi (s));
+ int num = atoi (s);
+
+ printf ("%d", num);
+
+ /* Make the blockage range values and function units used values easier
+ to read. */
+ if (attr->func_units_p)
+ {
+ if (num == -1)
+ printf (" /* units: none */");
+ else if (num >= 0)
+ write_unit_name (" /* units: ", num, " */");
+ else
+ {
+ int i;
+ 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
{
}
}
+ /* This default case should not be needed, but gcc's analysis is not
+ good enough to realize that the default case is not needed for the
+ second switch statement. */
+ printf (" default:\n abort ();\n");
printf (" }\n}\n\n");
}
\f
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 void
-fatal (s, a1, a2)
- char *s;
- char *a1, *a2;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genattrtab: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
printf (" default:\n");
printf (" return 1;\n");
- printf (" }\n}\n");
+ printf (" }\n}\n\n");
}
}
expand_units ();
printf ("#include \"config.h\"\n");
- printf ("#include <stdio.h>\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"insn-config.h\"\n");
printf ("#include \"recog.h\"\n");
printf ("#include \"real.h\"\n");
printf ("#include \"output.h\"\n");
printf ("#include \"insn-attr.h\"\n");
+ printf ("#include \"toplev.h\"\n");
printf ("\n");
printf ("#define operands recog_operand\n\n");
/* Write out constant delay slot info */
write_const_num_delay_slots ();
+ write_length_unit_log ();
+
fflush (stdout);
exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
/* NOTREACHED */