[12/13] .md-file enumerations: add define_enum_attr

Richard Sandiford rdsandiford@googlemail.com
Sun May 16 13:30:00 GMT 2010


This patch adds a define_enum_attr directive, which uses an existing
define_md_enum instead of a list of enumeration values.

Richard


gcc/
	* 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.

Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	2010-05-16 13:23:29.000000000 +0100
+++ gcc/doc/md.texi	2010-05-16 13:48:43.000000000 +0100
@@ -6692,9 +6692,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_md_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_md_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
@@ -7953,6 +7990,7 @@ it is convenient to define all synchroni
 values in @file{sync.md} rather than in the main @file{.md} file.
 
 @findex define_md_enum
+@anchor{define_md_enum}
 Another way of defining an enumeration is to use @code{define_md_enum}:
 
 @smallexample
@@ -7975,7 +8013,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_md_enum} can be used in attribute specifications
+(@pxref{define_enum_attr}).
 @end ifset
 @ifset INTERNALS
 @node Iterators
Index: gcc/rtl.def
===================================================================
--- gcc/rtl.def	2010-05-16 13:21:01.000000000 +0100
+++ gcc/rtl.def	2010-05-16 13:25:26.000000000 +0100
@@ -1198,6 +1198,12 @@ DEF_RTL_EXPR(DEFINE_INSN_RESERVATION, "d
    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)
 
Index: gcc/read-md.h
===================================================================
--- gcc/read-md.h	2010-05-16 13:21:01.000000000 +0100
+++ gcc/read-md.h	2010-05-16 13:25:26.000000000 +0100
@@ -135,5 +135,6 @@ extern const char *scan_comma_elt (const
 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);
Index: gcc/read-md.c
===================================================================
--- gcc/read-md.c	2010-05-16 13:21:01.000000000 +0100
+++ gcc/read-md.c	2010-05-16 13:25:26.000000000 +0100
@@ -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.  */
Index: gcc/genattr.c
===================================================================
--- gcc/genattr.c	2010-05-16 13:21:01.000000000 +0100
+++ gcc/genattr.c	2010-05-16 13:25:26.000000000 +0100
@@ -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)
Index: gcc/genattrtab.c
===================================================================
--- gcc/genattrtab.c	2010-05-16 13:21:01.000000000 +0100
+++ gcc/genattrtab.c	2010-05-16 13:25:26.000000000 +0100
@@ -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, in
 
     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, in
 	  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, in
 
       /* 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_cod
 	  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_md_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 *att
     }
   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 crea
 
   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 @@ main (int argc, char **argv)
 	  break;
 
 	case DEFINE_ATTR:
+	case DEFINE_ENUM_ATTR:
 	  gen_attr (desc, lineno);
 	  break;
 
Index: gcc/gensupport.c
===================================================================
--- gcc/gensupport.c	2010-05-16 13:21:01.000000000 +0100
+++ gcc/gensupport.c	2010-05-16 13:25:26.000000000 +0100
@@ -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;
 
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	2010-05-16 13:21:01.000000000 +0100
+++ gcc/config/mips/mips.h	2010-05-16 13:25:26.000000000 +0100
@@ -3040,10 +3040,6 @@ #define CPU_UNITS_QUERY 1
 #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:
 
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	2010-05-16 13:21:01.000000000 +0100
+++ gcc/config/mips/mips.md	2010-05-16 13:25:26.000000000 +0100
@@ -508,11 +508,9 @@ (define_attr "length" ""
 	  (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



More information about the Gcc-patches mailing list