diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f4630c7c410..77453d9ba5e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2010-06-10 Richard Sandiford + + * 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 * doc/md.texi (define_c_enum, define_enum): Document. diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 4d791023f14..4026bd73714 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -3035,10 +3035,6 @@ extern enum mips_code_readable_setting mips_code_readable; #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: diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 0f287755891..0ad21bd1783 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -508,11 +508,9 @@ (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 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 990863acccc..d0aa8646ede 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -6700,9 +6700,46 @@ distances. @xref{Insn Lengths}. 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 @@ -7961,6 +7998,7 @@ it is convenient to define all synchronization-specific enumeration 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 @@ -7983,7 +8021,11 @@ This directive implies: ]) @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 diff --git a/gcc/genattr.c b/gcc/genattr.c index 84399b8a677..e4609ca4174 100644 --- a/gcc/genattr.c +++ b/gcc/genattr.c @@ -49,27 +49,33 @@ gen_attr (rtx attr) 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)); - fputs ("};\n", stdout); - printf ("extern enum attr_%s get_attr_%s (%s);\n\n", - XSTR (attr, 0), XSTR (attr, 0), (is_const ? "void" : "rtx")); + 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); + + 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 @@ -122,7 +128,8 @@ main (int argc, char **argv) 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) diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index ac5c75e45d0..9fe1c5caa7c 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -171,6 +171,7 @@ struct attr_value 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. */ @@ -1901,11 +1902,13 @@ make_alternative_compare (int mask) 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; @@ -1923,16 +1926,12 @@ evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index) 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); @@ -1966,7 +1965,7 @@ evaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index) 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), @@ -1982,7 +1981,7 @@ evaluate_eq_attr (rtx exp, rtx value, int insn_code, int 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); @@ -2732,7 +2731,8 @@ simplify_test_exp (rtx exp, int insn_code, int 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; @@ -2900,13 +2900,30 @@ clear_struct_flag (rtx 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; @@ -2922,21 +2939,23 @@ gen_attr (rtx exp, int lineno) } 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) @@ -3319,8 +3338,8 @@ write_test_expr (rtx exp, int flags) /* 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 @@ -3612,7 +3631,9 @@ write_attr_get (struct attr_desc *attr) /* 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"); @@ -3869,7 +3890,7 @@ write_attr_valueq (struct attr_desc *attr, const char *s) } else { - write_upcase (attr->name); + write_upcase (attr->enum_name ? attr->enum_name : attr->name); printf ("_"); write_upcase (s); } @@ -4133,6 +4154,7 @@ find_attr (const char **name_p, int create) 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]; @@ -4459,6 +4481,7 @@ from the machine description file `md'. */\n\n"); break; case DEFINE_ATTR: + case DEFINE_ENUM_ATTR: gen_attr (desc, lineno); break; diff --git a/gcc/gensupport.c b/gcc/gensupport.c index 1389658609c..206e96b7c61 100644 --- a/gcc/gensupport.c +++ b/gcc/gensupport.c @@ -173,6 +173,7 @@ process_rtx (rtx desc, int lineno) break; case DEFINE_ATTR: + case DEFINE_ENUM_ATTR: queue_pattern (desc, &define_attr_tail, read_md_filename, lineno); break; diff --git a/gcc/read-md.c b/gcc/read-md.c index 90707b356d3..9c622912b3a 100644 --- a/gcc/read-md.c +++ b/gcc/read-md.c @@ -847,6 +847,14 @@ handle_enum (int lineno, bool md_p) } } +/* 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. */ diff --git a/gcc/read-md.h b/gcc/read-md.h index 94a5fbbc241..abcca51ac72 100644 --- a/gcc/read-md.h +++ b/gcc/read-md.h @@ -135,5 +135,6 @@ extern const char *scan_comma_elt (const char **); 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); diff --git a/gcc/rtl.def b/gcc/rtl.def index 8464d32e7f9..c4a3646afea 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -1198,6 +1198,12 @@ DEF_RTL_EXPR(DEFINE_INSN_RESERVATION, "define_insn_reservation", "sies", RTX_EXT 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)