+2010-06-10 Richard Sandiford <rdsandiford@googlemail.com>
+
+ * doc/md.texi (define_enum_attr): Document.
+ * rtl.def (DEFINE_ENUM_ATTR): New rtx.
+ * read-md.h (lookup_enum_type): Declare.
+ * read-md.c (lookup_enum_type): New function.
+ * genattr.c (gen_attr, main): Handle DEFINE_ENUM_ATTR.
+ * genattrtab.c (attr_desc): Add an enum_name field.
+ (evaluate_eq_attr): Take the associated attribute as argument.
+ Get the enum prefix from the enum_name field, if defined.
+ Use ACONCAT rather than a fixed-length buffer. Update recursive calls.
+ (simplify_test_exp): Pass attr to evaluate_eq_attr.
+ (add_attr_value): New function, split out from...
+ (gen_attr): ...here. Handle DEFINE_ENUM_ATTR.
+ (write_test_expr): Pass attr to evaluate_eq_attr.
+ (write_attr_get): Use the enum_name as the enum tag, if defined.
+ (write_attr_valueq): Use the enum_name as a prefix, if defined.
+ (find_attr): Initialize enum_name.
+ (main): Handle DEFINE_ENUM_ATTR.
+ * gensupport.c (process_rtx): Likewise.
+ * config/mips/mips.h (mips_tune_attr): Delete.
+ * config/mips/mips.md (cpu): Use define_attr_enum.
+
2010-06-10 Richard Sandiford <rdsandiford@googlemail.com>
* doc/md.texi (define_c_enum, define_enum): Document.
#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \
mips_final_prescan_insn (INSN, OPVEC, NOPERANDS)
-/* This is necessary to avoid a warning about comparing different enum
- types. */
-#define mips_tune_attr ((enum attr_cpu) mips_tune)
-
/* As on most targets, we want the .eh_frame section to be read-only where
possible. And as on most targets, this means two things:
(symbol_ref "mips_sync_loop_insns (insn, operands) * 4")
] (const_int 4)))
-;; Attribute describing the processor. This attribute must match exactly
-;; with the processor enumeration above.
-(define_attr "cpu"
- "r3000,4kc,4kp,5kc,5kf,20kc,24kc,24kf2_1,24kf1_1,74kc,74kf2_1,74kf1_1,74kf3_2,loongson_2e,loongson_2f,m4k,octeon,r3900,r6000,r4000,r4100,r4111,r4120,r4130,r4300,r4600,r4650,r5000,r5400,r5500,r7000,r8000,r9000,r10000,sb1,sb1a,sr71000,xlr"
- (const (symbol_ref "mips_tune_attr")))
+;; Attribute describing the processor.
+(define_enum_attr "cpu" "processor"
+ (const (symbol_ref "mips_tune")))
;; The type of hardware hazard associated with this instruction.
;; DELAY means that the next instruction cannot read the result
The @code{enabled} attribute can be defined to prevent certain
alternatives of an insn definition from being used during code
generation. @xref{Disable Insn Alternatives}.
-
@end table
+@findex define_enum_attr
+@anchor{define_enum_attr}
+Another way of defining an attribute is to use:
+
+@smallexample
+(define_enum_attr "@var{attr}" "@var{enum}" @var{default})
+@end smallexample
+
+This works in just the same way as @code{define_attr}, except that
+the list of values is taken from a separate enumeration called
+@var{enum} (@pxref{define_enum}). This form allows you to use
+the same list of values for several attributes without having to
+repeat the list each time. For example:
+
+@smallexample
+(define_enum "processor" [
+ model_a
+ model_b
+ @dots{}
+])
+(define_enum_attr "arch" "processor"
+ (const (symbol_ref "target_arch")))
+(define_enum_attr "tune" "processor"
+ (const (symbol_ref "target_tune")))
+@end smallexample
+
+defines the same attributes as:
+
+@smallexample
+(define_attr "arch" "model_a,model_b,@dots{}"
+ (const (symbol_ref "target_arch")))
+(define_attr "tune" "model_a,model_b,@dots{}"
+ (const (symbol_ref "target_tune")))
+@end smallexample
+
+but without duplicating the processor list. The second example defines two
+separate C enums (@code{attr_arch} and @code{attr_tune}) whereas the first
+defines a single C enum (@code{processor}).
@end ifset
@ifset INTERNALS
@node Expressions
values in @file{sync.md} rather than in the main @file{.md} file.
@findex define_enum
+@anchor{define_enum}
Another way of defining an enumeration is to use @code{define_enum}:
@smallexample
])
@end smallexample
+@findex define_enum_attr
where @var{cvaluei} is the capitalized form of @var{valuei}.
+However, unlike @code{define_c_enum}, the enumerations defined
+by @code{define_enum} can be used in attribute specifications
+(@pxref{define_enum_attr}).
@end ifset
@ifset INTERNALS
@node Iterators
printf ("#define HAVE_ATTR_%s\n", XSTR (attr, 0));
/* If numeric attribute, don't need to write an enum. */
- p = XSTR (attr, 1);
- if (*p == '\0')
- printf ("extern int get_attr_%s (%s);\n", XSTR (attr, 0),
- (is_const ? "void" : "rtx"));
+ if (GET_CODE (attr) == DEFINE_ENUM_ATTR)
+ printf ("extern enum %s get_attr_%s (%s);\n\n",
+ XSTR (attr, 1), XSTR (attr, 0), (is_const ? "void" : "rtx"));
else
{
- printf ("enum attr_%s {", XSTR (attr, 0));
-
- while ((tag = scan_comma_elt (&p)) != 0)
+ p = XSTR (attr, 1);
+ if (*p == '\0')
+ printf ("extern int get_attr_%s (%s);\n", XSTR (attr, 0),
+ (is_const ? "void" : "rtx"));
+ else
{
- write_upcase (XSTR (attr, 0));
- putchar ('_');
- while (tag != p)
- putchar (TOUPPER (*tag++));
- if (*p == ',')
- fputs (", ", stdout);
- }
+ printf ("enum attr_%s {", XSTR (attr, 0));
+
+ while ((tag = scan_comma_elt (&p)) != 0)
+ {
+ write_upcase (XSTR (attr, 0));
+ putchar ('_');
+ while (tag != p)
+ putchar (TOUPPER (*tag++));
+ if (*p == ',')
+ fputs (", ", stdout);
+ }
+ fputs ("};\n", stdout);
- fputs ("};\n", stdout);
- printf ("extern enum attr_%s get_attr_%s (%s);\n\n",
- XSTR (attr, 0), XSTR (attr, 0), (is_const ? "void" : "rtx"));
+ printf ("extern enum attr_%s get_attr_%s (%s);\n\n",
+ XSTR (attr, 0), XSTR (attr, 0), (is_const ? "void" : "rtx"));
+ }
}
/* If `length' attribute, write additional function definitions and define
if (desc == NULL)
break;
- if (GET_CODE (desc) == DEFINE_ATTR)
+ if (GET_CODE (desc) == DEFINE_ATTR
+ || GET_CODE (desc) == DEFINE_ENUM_ATTR)
gen_attr (desc);
else if (GET_CODE (desc) == DEFINE_DELAY)
struct attr_desc
{
char *name; /* Name of attribute. */
+ const char *enum_name; /* Enum name for DEFINE_ENUM_NAME. */
struct attr_desc *next; /* Next attribute. */
struct attr_value *first_value; /* First value of this attribute. */
struct attr_value *default_val; /* Default value for this attribute. */
computation. If a test condition involves an address, we leave the EQ_ATTR
intact because addresses are only valid for the `length' attribute.
- EXP is the EQ_ATTR expression and VALUE is the value of that attribute
- for the insn corresponding to INSN_CODE and INSN_INDEX. */
+ EXP is the EQ_ATTR expression and ATTR is the attribute to which
+ it refers. VALUE is the value of that attribute for the insn
+ corresponding to INSN_CODE and INSN_INDEX. */
static rtx
-evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index)
+evaluate_eq_attr (rtx exp, struct attr_desc *attr, rtx value,
+ int insn_code, int insn_index)
{
rtx orexp, andexp;
rtx right;
case SYMBOL_REF:
{
- char *p;
- char string[256];
+ const char *prefix;
+ char *string, *p;
gcc_assert (GET_CODE (exp) == EQ_ATTR);
- gcc_assert (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2
- <= 256);
-
- strcpy (string, XSTR (exp, 0));
- strcat (string, "_");
- strcat (string, XSTR (exp, 1));
+ prefix = attr->enum_name ? attr->enum_name : attr->name;
+ string = ACONCAT ((prefix, "_", XSTR (exp, 1), NULL));
for (p = string; *p; p++)
*p = TOUPPER (*p);
right = insert_right_side (AND, andexp, this_cond,
insn_code, insn_index);
right = insert_right_side (AND, right,
- evaluate_eq_attr (exp,
+ evaluate_eq_attr (exp, attr,
XVECEXP (value, 0,
i + 1),
insn_code, insn_index),
/* Handle the default case. */
right = insert_right_side (AND, andexp,
- evaluate_eq_attr (exp, XEXP (value, 1),
+ evaluate_eq_attr (exp, attr, XEXP (value, 1),
insn_code, insn_index),
insn_code, insn_index);
newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
if (av)
{
got_av:
- x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
+ x = evaluate_eq_attr (exp, attr, av->value,
+ insn_code, insn_index);
x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
if (attr_rtx_cost(x) < 20)
return x;
}
}
-/* Create table entries for DEFINE_ATTR. */
+/* Add attribute value NAME to the beginning of ATTR's list. */
+
+static void
+add_attr_value (struct attr_desc *attr, const char *name)
+{
+ struct attr_value *av;
+
+ av = oballoc (struct attr_value);
+ av->value = attr_rtx (CONST_STRING, name);
+ av->next = attr->first_value;
+ attr->first_value = av;
+ av->first_insn = NULL;
+ av->num_insns = 0;
+ av->has_asm_insn = 0;
+}
+
+/* Create table entries for DEFINE_ATTR or DEFINE_ENUM_ATTR. */
static void
gen_attr (rtx exp, int lineno)
{
+ struct enum_type *et;
+ struct enum_value *ev;
struct attr_desc *attr;
- struct attr_value *av;
const char *name_ptr;
char *p;
}
attr->lineno = lineno;
- if (*XSTR (exp, 1) == '\0')
+ if (GET_CODE (exp) == DEFINE_ENUM_ATTR)
+ {
+ attr->enum_name = XSTR (exp, 1);
+ et = lookup_enum_type (XSTR (exp, 1));
+ if (!et || !et->md_p)
+ error_with_line (lineno, "No define_enum called `%s' defined",
+ attr->name);
+ for (ev = et->values; ev; ev = ev->next)
+ add_attr_value (attr, ev->name);
+ }
+ else if (*XSTR (exp, 1) == '\0')
attr->is_numeric = 1;
else
{
name_ptr = XSTR (exp, 1);
while ((p = next_comma_elt (&name_ptr)) != NULL)
- {
- av = oballoc (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;
- }
+ add_attr_value (attr, p);
}
if (GET_CODE (XEXP (exp, 2)) == CONST)
/* Now is the time to expand the value of a constant attribute. */
if (attr->is_const)
{
- write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
- -2, -2),
+ write_test_expr (evaluate_eq_attr (exp, attr,
+ attr->default_val->value, -2, -2),
flags);
}
else
/* Write out start of function, then all values with explicit `case' lines,
then a `default', then the value with the most uses. */
- if (!attr->is_numeric)
+ if (attr->enum_name)
+ printf ("enum %s\n", attr->enum_name);
+ else if (!attr->is_numeric)
printf ("enum attr_%s\n", attr->name);
else
printf ("int\n");
}
else
{
- write_upcase (attr->name);
+ write_upcase (attr->enum_name ? attr->enum_name : attr->name);
printf ("_");
write_upcase (s);
}
attr = oballoc (struct attr_desc);
attr->name = DEF_ATTR_STRING (name);
+ attr->enum_name = 0;
attr->first_value = attr->default_val = NULL;
attr->is_numeric = attr->is_const = attr->is_special = 0;
attr->next = attrs[index];
break;
case DEFINE_ATTR:
+ case DEFINE_ENUM_ATTR:
gen_attr (desc, lineno);
break;
break;
case DEFINE_ATTR:
+ case DEFINE_ENUM_ATTR:
queue_pattern (desc, &define_attr_tail, read_md_filename, lineno);
break;
}
}
+/* Try to find the definition of the given enum. Return null on failure. */
+
+struct enum_type *
+lookup_enum_type (const char *name)
+{
+ return (struct enum_type *) htab_find (enum_types, &name);
+}
+
/* For every enum definition, call CALLBACK with two arguments:
a pointer to the constant definition and INFO. Stop when CALLBACK
returns zero. */
extern void upcase_string (char *);
extern void traverse_md_constants (htab_trav, void *);
extern void traverse_enum_types (htab_trav, void *);
+extern struct enum_type *lookup_enum_type (const char *);
extern bool read_md_files (int, char **, bool (*) (const char *),
directive_handler_t);
3rd operand: expression for the default value of the attribute. */
DEF_RTL_EXPR(DEFINE_ATTR, "define_attr", "sse", RTX_EXTRA)
+/* Definition of an insn attribute that uses an existing enumerated type.
+ 1st operand: name of the attribute
+ 2nd operand: the name of the enumerated type
+ 3rd operand: expression for the default value of the attribute. */
+DEF_RTL_EXPR(DEFINE_ENUM_ATTR, "define_enum_attr", "sse", RTX_EXTRA)
+
/* Marker for the name of an attribute. */
DEF_RTL_EXPR(ATTR, "attr", "s", RTX_EXTRA)