public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Constraint matching TLC
@ 2014-06-05 21:25 Richard Sandiford
  2014-06-05 21:27 ` [PATCH 1/8] Faster checks for constraint types Richard Sandiford
                   ` (7 more replies)
  0 siblings, 8 replies; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:25 UTC (permalink / raw)
  To: gcc-patches

This series of patches tries to improve the way that constraints are matched.
It breaks down into three parts:

(a) the first three patches speed up the routines generated by genpreds.c.
(b) the fourth patch avoids repeated calls to lookup_constraint.
(c) the final four patches (which are really a single change split up
    for review purposes) use .md files to define all standard constraints
    except 'g'.

Overall the series gives a 1% compile-time improvement in my favourite
-O0 fold-const.ii test.  Each of the three parts gives a reproducible
speed-up compared to the previous state.  Hopefully it's also a cleanup;
diffstat for the series (plus the single_reg_class patch I posted earlier) is:

 20 files changed, 575 insertions(+), 1217 deletions(-)

Tested on x86_64-linux-gnu.  Also tested by compiling gcc.dg, g++.dg
and gcc.c-torture at -O2 for one target per config/ directory.
There were no changes in asm output.  OK to install?

Thanks,
Richard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 1/8] Faster checks for constraint types
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
@ 2014-06-05 21:27 ` Richard Sandiford
  2014-06-10 18:42   ` Jeff Law
  2014-06-05 21:29 ` [PATCH 2/8] Speed up lookup_constraint Richard Sandiford
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:27 UTC (permalink / raw)
  To: gcc-patches

genpreds.c defines routines insn_extra_memory_constraint and
insn_extra_address_constraint for testing whether a particular
constraint_num is a memory or address constraint.  At the moment it uses
an out-of-line switch-based function to do this, but if we organise the
constraint_num enum differently, we can use a simple range test instead.

Similarly, if we group register constraints together, we can handle
reg_class_for_constraint for non-register constraints inline.
The same goes for constraint_satisfied_p and register constraints.
The point is that constraints are either register constraints or things
that could be satisfied by constraint_satisfied_p, never both, and
exposing this helps with jump threading.  This becomes more important
with the last half of the series.

Richard


gcc/
	* doc/md.texi (regclass_for_constraint): Rename to...
	(reg_class_for_constraint): ...this.
	* genpreds.c (num_constraints, enum_order, register_start)
	(register_end, satisfied_start, memory_start, memory_end)
	(address_start, address_end): New variables.
	(add_constraint): Count the number of constraints.
	(choose_enum_order): New function.
	(write_enum_constraint_num): Iterate over enum_order.
	(write_regclass_for_constraint): Rename to...
	(write_reg_class_for_constraint_1): ...this and update output
	accordingly.
	(write_constraint_satisfied_p): Rename to...
	(write_constraint_satisfied_p_1): ...this and update output
	accordingly.  Do nothing if all extra constraints are register
	constraints.
	(write_insn_extra_memory_constraint): Delete.
	(write_insn_extra_address_constraint): Delete.
	(write_range_function): New function.
	(write_tm_preds_h): Define constraint_satisfied_p and
	reg_class_for_constraint as inline functions that do a range check
	before calling the out-of-line function.  Use write_range_function
	to implement insn_extra_{register,memory,address}_constraint,
	the first of which is new.
	(write_insn_preds_c): Update after above changes to write_* functions.
	(main): Call choose_enum_order.

Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	2014-06-04 18:14:38.519717596 +0100
+++ gcc/doc/md.texi	2014-06-04 18:30:51.979437902 +0100
@@ -4414,7 +4414,7 @@ specifies a register constraint, this fu
 @code{false}.
 @end deftypefun
 
-@deftypefun {enum reg_class} regclass_for_constraint (enum constraint_num @var{c})
+@deftypefun {enum reg_class} reg_class_for_constraint (enum constraint_num @var{c})
 Returns the register class associated with @var{c}.  If @var{c} is not
 a register constraint, or those registers are not available for the
 currently selected subtarget, returns @code{NO_REGS}.
Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-04 18:14:38.519717596 +0100
+++ gcc/genpreds.c	2014-06-04 18:30:53.652452891 +0100
@@ -685,6 +685,13 @@ static const char const_dbl_constraints[
 static bool have_extra_constraints;
 static bool have_const_int_constraints;
 static bool have_const_dbl_constraints;
+static unsigned int num_constraints;
+
+static const constraint_data **enum_order;
+static unsigned int register_start, register_end;
+static unsigned int satisfied_start;
+static unsigned int memory_start, memory_end;
+static unsigned int address_start, address_end;
 
 /* Convert NAME, which contains angle brackets and/or underscores, to
    a string that can be used as part of a C identifier.  The string
@@ -884,6 +891,7 @@ add_constraint (const char *name, const
   have_extra_constraints |= c->is_extra;
   have_memory_constraints |= c->is_memory;
   have_address_constraints |= c->is_address;
+  num_constraints += 1;
 }
 
 /* Process a DEFINE_CONSTRAINT, DEFINE_MEMORY_CONSTRAINT, or
@@ -904,19 +912,54 @@ process_define_register_constraint (rtx
   add_constraint (XSTR (c, 0), XSTR (c, 1), 0, false, false, lineno);
 }
 
+/* Put the constraints into enum order.  We want to keep constraints
+   of the same type together so that query functions can be simple
+   range checks.  */
+static void
+choose_enum_order (void)
+{
+  struct constraint_data *c;
+
+  enum_order = XNEWVEC (const constraint_data *, num_constraints);
+  unsigned int next = 0;
+
+  register_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_register)
+      enum_order[next++] = c;
+  register_end = next;
+
+  satisfied_start = next;
+
+  memory_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_memory)
+      enum_order[next++] = c;
+  memory_end = next;
+
+  address_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_address)
+      enum_order[next++] = c;
+  address_end = next;
+
+  FOR_ALL_CONSTRAINTS (c)
+    if (!c->is_register && !c->is_memory && !c->is_address)
+      enum_order[next++] = c;
+  gcc_assert (next == num_constraints);
+}
+
 /* Write out an enumeration with one entry per machine-specific
    constraint.  */
 static void
 write_enum_constraint_num (void)
 {
-  struct constraint_data *c;
-
   fputs ("#define CONSTRAINT_NUM_DEFINED_P 1\n", stdout);
   fputs ("enum constraint_num\n"
 	 "{\n"
 	 "  CONSTRAINT__UNKNOWN = 0", stdout);
-  FOR_ALL_CONSTRAINTS (c)
-    printf (",\n  CONSTRAINT_%s", c->c_name);
+  for (unsigned int i = 0; i < num_constraints; ++i)
+    printf (",\n  CONSTRAINT_%s", enum_order[i]->c_name);
   puts (",\n  CONSTRAINT__LIMIT\n};\n");
 }
 
@@ -1010,12 +1053,12 @@ write_insn_constraint_len (void)
 /* Write out the function which computes the register class corresponding
    to a register constraint.  */
 static void
-write_regclass_for_constraint (void)
+write_reg_class_for_constraint_1 (void)
 {
   struct constraint_data *c;
 
   puts ("enum reg_class\n"
-	"regclass_for_constraint (enum constraint_num c)\n"
+	"reg_class_for_constraint_1 (enum constraint_num c)\n"
 	"{\n"
 	"  switch (c)\n"
 	"    {");
@@ -1100,12 +1143,15 @@ #define GCC_TM_CONSTRS_H\n");
    a CONSTRAINT_xxx constant to one of the predicate functions generated
    above.  */
 static void
-write_constraint_satisfied_p (void)
+write_constraint_satisfied_p_1 (void)
 {
   struct constraint_data *c;
 
+  if (satisfied_start == num_constraints)
+    return;
+
   puts ("bool\n"
-	"constraint_satisfied_p (rtx op, enum constraint_num c)\n"
+	"constraint_satisfied_p_1 (rtx op, enum constraint_num c)\n"
 	"{\n"
 	"  switch (c)\n"
 	"    {");
@@ -1153,55 +1199,26 @@ write_insn_const_int_ok_for_constraint (
 	"  return false;\n"
 	"}\n");
 }
-
-
-/* Write out the function which computes whether a given constraint is
-   a memory constraint.  */
-static void
-write_insn_extra_memory_constraint (void)
-{
-  struct constraint_data *c;
-
-  puts ("bool\n"
-	"insn_extra_memory_constraint (enum constraint_num c)\n"
-	"{\n"
-	"  switch (c)\n"
-	"    {");
-
-  FOR_ALL_CONSTRAINTS (c)
-    if (c->is_memory)
-      printf ("    case CONSTRAINT_%s:\n      return true;\n\n", c->c_name);
-
-  puts ("    default: break;\n"
-	"    }\n"
-	"  return false;\n"
-	"}\n");
-}
-
-/* Write out the function which computes whether a given constraint is
-   an address constraint.  */
+\f
+/* Write a definition for a function NAME that returns true if a given
+   constraint_num is in the range [START, END).  */
 static void
-write_insn_extra_address_constraint (void)
+write_range_function (const char *name, unsigned int start, unsigned int end)
 {
-  struct constraint_data *c;
-
-  puts ("bool\n"
-	"insn_extra_address_constraint (enum constraint_num c)\n"
-	"{\n"
-	"  switch (c)\n"
-	"    {");
-
-  FOR_ALL_CONSTRAINTS (c)
-    if (c->is_address)
-      printf ("    case CONSTRAINT_%s:\n      return true;\n\n", c->c_name);
-
-  puts ("    default: break;\n"
-	"    }\n"
-	"  return false;\n"
-	"}\n");
+  printf ("static inline bool\n");
+  if (start != end)
+    printf ("%s (enum constraint_num c)\n"
+	    "{\n"
+	    "  return c >= CONSTRAINT_%s && c <= CONSTRAINT_%s;\n"
+	    "}\n\n",
+	    name, enum_order[start]->c_name, enum_order[end - 1]->c_name);
+  else
+    printf ("%s (enum constraint_num)\n"
+	    "{\n"
+	    "  return false;\n"
+	    "}\n\n", name);
 }
 
-\f
 /* Write tm-preds.h.  Unfortunately, it is impossible to forward-declare
    an enumeration in portable C, so we have to condition all these
    prototypes on HAVE_MACHINE_MODES.  */
@@ -1228,8 +1245,36 @@ #define GCC_TM_PREDS_H\n\
   if (constraint_max_namelen > 0)
     {
       write_enum_constraint_num ();
-      puts ("extern enum constraint_num lookup_constraint (const char *);\n"
-	    "extern bool constraint_satisfied_p (rtx, enum constraint_num);\n");
+      puts ("extern enum constraint_num lookup_constraint (const char *);");
+      if (satisfied_start == num_constraints)
+	puts ("/* Return true if X satisfies constraint C.  */\n"
+	      "\n"
+	      "static inline bool\n"
+	      "constraint_satisfied_p (rtx, enum constraint_num)\n"
+	      "{\n"
+	      "  return false;\n"
+	      "}\n");
+      else
+	printf ("extern bool constraint_satisfied_p_1 (rtx,"
+		" enum constraint_num);\n"
+		"\n"
+		"/* Return true if X satisfies constraint C.  */\n"
+		"\n"
+		"static inline bool\n"
+		"constraint_satisfied_p (rtx x, enum constraint_num c)\n"
+		"{\n"
+		"  return c >= CONSTRAINT_%s"
+		" && constraint_satisfied_p_1 (x, c);\n"
+		"}\n"
+		"\n",
+		enum_order[satisfied_start]->name);
+
+      write_range_function ("insn_extra_register_constraint",
+			    register_start, register_end);
+      write_range_function ("insn_extra_memory_constraint",
+			    memory_start, memory_end);
+      write_range_function ("insn_extra_address_constraint",
+			    address_start, address_end);
 
       if (constraint_max_namelen > 1)
         {
@@ -1240,14 +1285,28 @@ #define GCC_TM_PREDS_H\n\
       else
 	puts ("#define CONSTRAINT_LEN(c_,s_) 1\n");
       if (have_register_constraints)
-	puts ("extern enum reg_class regclass_for_constraint "
+	puts ("extern enum reg_class reg_class_for_constraint_1 "
 	      "(enum constraint_num);\n"
+	      "\n"
+	      "static inline enum reg_class\n"
+	      "reg_class_for_constraint (enum constraint_num c)\n"
+	      "{\n"
+	      "  if (insn_extra_register_constraint (c))\n"
+	      "    return reg_class_for_constraint_1 (c);\n"
+	      "  return NO_REGS;\n"
+	      "}\n"
+	      "\n"
 	      "#define REG_CLASS_FROM_CONSTRAINT(c_,s_) \\\n"
-	      "    regclass_for_constraint (lookup_constraint (s_))\n"
+	      "    reg_class_for_constraint (lookup_constraint (s_))\n"
 	      "#define REG_CLASS_FOR_CONSTRAINT(x_) \\\n"
-	      "    regclass_for_constraint (x_)\n");
+	      "    reg_class_for_constraint (x_)\n");
       else
-	puts ("#define REG_CLASS_FROM_CONSTRAINT(c_,s_) NO_REGS\n"
+	puts ("static inline enum reg_class\n"
+	      "reg_class_for_constraint (enum constraint_num)\n"
+	      "{\n"
+	      "  return NO_REGS;\n"
+	      "}\n\n"
+	      "#define REG_CLASS_FROM_CONSTRAINT(c_,s_) NO_REGS\n"
 	      "#define REG_CLASS_FOR_CONSTRAINT(x_) \\\n"
 	      "    NO_REGS\n");
       if (have_const_int_constraints)
@@ -1265,16 +1324,12 @@ #define GCC_TM_PREDS_H\n\
 	puts ("#define EXTRA_CONSTRAINT_STR(v_,c_,s_) \\\n"
 	      "    constraint_satisfied_p (v_, lookup_constraint (s_))\n");
       if (have_memory_constraints)
-	puts ("extern bool "
-	      "insn_extra_memory_constraint (enum constraint_num);\n"
-	      "#define EXTRA_MEMORY_CONSTRAINT(c_,s_) "
+	puts ("#define EXTRA_MEMORY_CONSTRAINT(c_,s_) "
 	      "insn_extra_memory_constraint (lookup_constraint (s_))\n");
       else
 	puts ("#define EXTRA_MEMORY_CONSTRAINT(c_,s_) false\n");
       if (have_address_constraints)
-	puts ("extern bool "
-	      "insn_extra_address_constraint (enum constraint_num);\n"
-	      "#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) "
+	puts ("#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) "
 	      "insn_extra_address_constraint (lookup_constraint (s_))\n");
       else
 	puts ("#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) false\n");
@@ -1330,16 +1385,11 @@ write_insn_preds_c (void)
     {
       write_lookup_constraint ();
       if (have_register_constraints)
-	write_regclass_for_constraint ();
-      write_constraint_satisfied_p ();
+	write_reg_class_for_constraint_1 ();
+      write_constraint_satisfied_p_1 ();
 
       if (have_const_int_constraints)
 	write_insn_const_int_ok_for_constraint ();
-
-      if (have_memory_constraints)
-	write_insn_extra_memory_constraint ();
-      if (have_address_constraints)
-	write_insn_extra_address_constraint ();
     }
 }
 
@@ -1399,6 +1449,8 @@ main (int argc, char **argv)
 	break;
       }
 
+  choose_enum_order ();
+
   if (gen_header)
     write_tm_preds_h ();
   else if (gen_constrs)

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 2/8] Speed up lookup_constraint
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
  2014-06-05 21:27 ` [PATCH 1/8] Faster checks for constraint types Richard Sandiford
@ 2014-06-05 21:29 ` Richard Sandiford
  2014-06-10 18:41   ` Jeff Law
  2014-06-05 21:31 ` [PATCH 3/8] Speed up constraint_satisfied_p Richard Sandiford
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:29 UTC (permalink / raw)
  To: gcc-patches

lookup_constraint is also an out-of-line switch-based function.
Since most constraints are still single-letter ones, it should be
more efficient to have a lookup array for the single-character case
and an out-of-line function for the more complicated ones.  This becomes
even more important with the latter half of the series (which isn't as
much of a win otherwise).

Richard


gcc/
	* genpreds.c (write_lookup_constraint): Rename to...
	(write_lookup_constraint_1): ...this.
	(write_lookup_constraint_array): New function.
	(write_tm_preds_h): Define lookup_constraint as an inline function
	that uses write_lookup_constraint_array where possible.
	(write_insn_preds_c): Update for the changes above.

Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-05 21:05:45.308958640 +0100
+++ gcc/genpreds.c	2014-06-05 21:05:45.972964371 +0100
@@ -966,11 +966,11 @@ write_enum_constraint_num (void)
 /* Write out a function which looks at a string and determines what
    constraint name, if any, it begins with.  */
 static void
-write_lookup_constraint (void)
+write_lookup_constraint_1 (void)
 {
   unsigned int i;
   puts ("enum constraint_num\n"
-	"lookup_constraint (const char *str)\n"
+	"lookup_constraint_1 (const char *str)\n"
 	"{\n"
 	"  switch (str[0])\n"
 	"    {");
@@ -1005,6 +1005,29 @@ write_lookup_constraint (void)
 	"}\n");
 }
 
+/* Write out an array that maps single-letter characters to their
+   constraints (if that fits in a character) or 255 if lookup_constraint_1
+   must be called.  */
+static void
+write_lookup_constraint_array (void)
+{
+  unsigned int i;
+  printf ("const unsigned char lookup_constraint_array[] = {\n  ");
+  for (i = 0; i < ARRAY_SIZE (constraints_by_letter_table); i++)
+    {
+      if (i != 0)
+	printf (",\n  ");
+      struct constraint_data *c = constraints_by_letter_table[i];
+      if (!c)
+	printf ("CONSTRAINT__UNKNOWN");
+      else if (c->namelen == 1)
+	printf ("MIN ((int) CONSTRAINT_%s, (int) UCHAR_MAX)", c->c_name);
+      else
+	printf ("UCHAR_MAX");
+    }
+  printf ("\n};\n\n");
+}
+
 /* Write out a function which looks at a string and determines what
    the constraint name length is.  */
 static void
@@ -1245,7 +1268,22 @@ #define GCC_TM_PREDS_H\n\
   if (constraint_max_namelen > 0)
     {
       write_enum_constraint_num ();
-      puts ("extern enum constraint_num lookup_constraint (const char *);");
+      puts ("extern enum constraint_num lookup_constraint_1 (const char *);\n"
+	    "extern const unsigned char lookup_constraint_array[];\n"
+	    "\n"
+	    "/* Return the constraint at the beginning of P, or"
+	    " CONSTRAINT__UNKNOWN if it\n"
+	    "   isn't recognized.  */\n"
+	    "\n"
+	    "static inline enum constraint_num\n"
+	    "lookup_constraint (const char *p)\n"
+	    "{\n"
+	    "  unsigned int index = lookup_constraint_array"
+	    "[(unsigned char) *p];\n"
+	    "  return (index == UCHAR_MAX\n"
+	    "          ? lookup_constraint_1 (p)\n"
+	    "          : (enum constraint_num) index);\n"
+	    "}\n");
       if (satisfied_start == num_constraints)
 	puts ("/* Return true if X satisfies constraint C.  */\n"
 	      "\n"
@@ -1383,7 +1421,8 @@ write_insn_preds_c (void)
 
   if (constraint_max_namelen > 0)
     {
-      write_lookup_constraint ();
+      write_lookup_constraint_1 ();
+      write_lookup_constraint_array ();
       if (have_register_constraints)
 	write_reg_class_for_constraint_1 ();
       write_constraint_satisfied_p_1 ();

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 3/8] Speed up constraint_satisfied_p
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
  2014-06-05 21:27 ` [PATCH 1/8] Faster checks for constraint types Richard Sandiford
  2014-06-05 21:29 ` [PATCH 2/8] Speed up lookup_constraint Richard Sandiford
@ 2014-06-05 21:31 ` Richard Sandiford
  2014-06-10 18:42   ` Jeff Law
  2014-06-05 21:32 ` [PATCH 4/8] Remove old macros and make lookup_constraint explicit Richard Sandiford
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:31 UTC (permalink / raw)
  To: gcc-patches

After the earlier changes, the only important function that switches on
constraint_num is constraint_satisfied_p (now constraint_satisfied_p_1).
Since constraint_num is a dense enum, it seems faster to use a jump
table instead.  In many cases this allows the handling function to be
a simple sibcall to something like a predicate.

Richard


gcc/
	* genpreds.c (write_constraint_satisfied_p_1): Replace with...
	(write_constraint_satisfied_p_array): ...this new function.
	(write_tm_preds_h): Replace write_constraint_satisfied_p_1 with
	an array.
	(write_insn_preds_c): Update accordingly.

Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-05 21:05:45.972964371 +0100
+++ gcc/genpreds.c	2014-06-05 21:05:49.372993717 +0100
@@ -1166,29 +1166,19 @@ #define GCC_TM_CONSTRS_H\n");
    a CONSTRAINT_xxx constant to one of the predicate functions generated
    above.  */
 static void
-write_constraint_satisfied_p_1 (void)
+write_constraint_satisfied_p_array (void)
 {
-  struct constraint_data *c;
-
   if (satisfied_start == num_constraints)
     return;
 
-  puts ("bool\n"
-	"constraint_satisfied_p_1 (rtx op, enum constraint_num c)\n"
-	"{\n"
-	"  switch (c)\n"
-	"    {");
-
-  FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register)
-      printf ("    case CONSTRAINT_%s: "
-	      "return satisfies_constraint_%s (op);\n",
-	      c->c_name, c->c_name);
-
-  puts ("    default: break;\n"
-	"    }\n"
-	"  return false;\n"
-	"}\n");
+  printf ("bool (*constraint_satisfied_p_array[]) (rtx) = {\n  ");
+  for (unsigned int i = satisfied_start; i < num_constraints; ++i)
+    {
+      if (i != satisfied_start)
+	printf (",\n  ");
+      printf ("satisfies_constraint_%s", enum_order[i]->c_name);
+    }
+  printf ("\n};\n\n");
 }
 
 /* Write out the function which computes whether a given value matches
@@ -1293,16 +1283,15 @@ #define GCC_TM_PREDS_H\n\
 	      "  return false;\n"
 	      "}\n");
       else
-	printf ("extern bool constraint_satisfied_p_1 (rtx,"
-		" enum constraint_num);\n"
+	printf ("extern bool (*constraint_satisfied_p_array[]) (rtx);\n"
 		"\n"
 		"/* Return true if X satisfies constraint C.  */\n"
 		"\n"
 		"static inline bool\n"
 		"constraint_satisfied_p (rtx x, enum constraint_num c)\n"
 		"{\n"
-		"  return c >= CONSTRAINT_%s"
-		" && constraint_satisfied_p_1 (x, c);\n"
+		"  int i = (int) c - (int) CONSTRAINT_%s;\n"
+		"  return i >= 0 && constraint_satisfied_p_array[i] (x);\n"
 		"}\n"
 		"\n",
 		enum_order[satisfied_start]->name);
@@ -1425,7 +1414,7 @@ write_insn_preds_c (void)
       write_lookup_constraint_array ();
       if (have_register_constraints)
 	write_reg_class_for_constraint_1 ();
-      write_constraint_satisfied_p_1 ();
+      write_constraint_satisfied_p_array ();
 
       if (have_const_int_constraints)
 	write_insn_const_int_ok_for_constraint ();

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 4/8] Remove old macros and make lookup_constraint explicit
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
                   ` (2 preceding siblings ...)
  2014-06-05 21:31 ` [PATCH 3/8] Speed up constraint_satisfied_p Richard Sandiford
@ 2014-06-05 21:32 ` Richard Sandiford
  2014-06-10 20:53   ` Jeff Law
  2014-06-05 21:33 ` [PATCH 5/8] Remove unused operand_alternative fields Richard Sandiford
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:32 UTC (permalink / raw)
  To: gcc-patches

Now that all extra constraints are defined in .md files, there's no real
need for the old REG_CLASS_FROM_CONSTRAINT-style macros.  The macros also
seem dangerous performance-wise, since each one contains an embedded call to
lookup_constraint.  This means that code like:

		    if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
		      {
			if (EXTRA_MEMORY_CONSTRAINT (c, p))
			  ... EXTRA_CONSTRAINT_STR ...
			if (EXTRA_ADDRESS_CONSTRAINT (c, p))
			  ... EXTRA_CONSTRAINT_STR ...
			... EXTRA_CONSTRAINT_STR ...
		      }
		    ...REG_CLASS_FROM_CONSTRAINT...

looks up the same constraint several times.

This patch replaces all uses of:

    REG_CLASS_FROM_CONSTRAINT
    REG_CLASS_FOR_CONSTRAINT
    EXTRA_CONSTRAINT_STR
    EXTRA_MEMORY_CONSTRAINT
    EXTRA_ADDRESS_CONSTRAINT

with separate calls to lookup_constraint and the underlying query function.
It poisons the old macros as a way of protecting against accidental use
(e.g. in #ifdef EXTRA_CONSTRAINT_STR blocks).

Several places want to handle each specific type of constraint in a
different way, so I added a convenience function for classifying constraints
into a type enum.  This also makes the range checks more efficient.
I've treated CONSTRAINT__UNKNOWN as a register constraint (the first type)
since that avoids one more range check and means that each consumer doesn't
have to handle non-constraints specially.  The range check in
reg_class_for_constraint already ensures that the CONSTRAINT__UNKNOWN->
NO_REGS mapping is inline.

Richard


gcc/
	* system.h (REG_CLASS_FROM_CONSTRAINT): Poison.
	(REG_CLASS_FOR_CONSTRAINT, EXTRA_CONSTRAINT_STR): Likewise.
	(EXTRA_MEMORY_CONSTRAINT, EXTRA_ADDRESS_CONSTRAINT): Likewise.
	* genpreds.c (print_type_tree): New function.
	(write_tm_preds_h): Remove REG_CLASS_FROM_CONSTRAINT,
	REG_CLASS_FOR_CONSTRAINT, EXTRA_MEMORY_CONSTRAINT,
	EXTRA_ADDRESS_CONSTRAINT and EXTRA_CONSTRAINT_STR.
	Write out enum constraint_type and get_constraint_type.
	* lra-constraints.c (satisfies_memory_constraint_p): Take a
	constraint_num rather than a constraint string.
	(satisfies_address_constraint_p): Likewise.
	(reg_class_from_constraints): Avoid old constraint macros.
	(process_alt_operands, process_address_1): Likewise.
	(curr_insn_transform): Likewise.
	* ira-costs.c (record_reg_classes): Likewise.
	(record_operand_costs): Likewise.
	* ira-lives.c (single_reg_class): Likewise.
	(ira_implicitly_set_insn_hard_regs): Likewise.
	* ira.c (ira_setup_alts, ira_get_dup_out_num): Likewise.
	* postreload.c (reload_cse_simplify_operands): Likewise.
	* recog.c (asm_operand_ok, preprocess_constraints): Likewise.
	(constrain_operands, peep2_find_free_register): Likewise.
	* reload.c (push_secondary_reload, scratch_reload_class): Likewise.
	(find_reloads, alternative_allows_const_pool_ref): Likewise.
	* reload1.c (maybe_fix_stack_asms): Likewise.
	* stmt.c (parse_output_constraint, parse_input_constraint): Likewise.
	* targhooks.c (default_secondary_reload): Likewise.
	* config/m32c/m32c.c (m32c_matches_constraint_p): Avoid reference
	to EXTRA_CONSTRAINT_STR.
	* config/sparc/constraints.md (U): Likewise REG_CLASS_FROM_CONSTRAINT.

Index: gcc/system.h
===================================================================
--- gcc/system.h	2014-06-05 21:06:52.721540056 +0100
+++ gcc/system.h	2014-06-05 21:45:00.219282847 +0100
@@ -930,7 +930,10 @@ #define realloc xrealloc
         GO_IF_MODE_DEPENDENT_ADDRESS DELAY_SLOTS_FOR_EPILOGUE              \
         ELIGIBLE_FOR_EPILOGUE_DELAY TARGET_C99_FUNCTIONS TARGET_HAS_SINCOS \
 	REG_CLASS_FROM_LETTER CONST_OK_FOR_LETTER_P			   \
-	CONST_DOUBLE_OK_FOR_LETTER_P EXTRA_CONSTRAINT
+	CONST_DOUBLE_OK_FOR_LETTER_P EXTRA_CONSTRAINT			   \
+	REG_CLASS_FROM_CONSTRAINT REG_CLASS_FOR_CONSTRAINT		   \
+	EXTRA_CONSTRAINT_STR EXTRA_MEMORY_CONSTRAINT			   \
+	EXTRA_ADDRESS_CONSTRAINT
 
 /* Hooks that are no longer used.  */
  #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE	\
Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-05 21:45:00.187282566 +0100
+++ gcc/genpreds.c	2014-06-05 21:45:00.211282777 +0100
@@ -1232,6 +1232,33 @@ write_range_function (const char *name,
 	    "}\n\n", name);
 }
 
+/* VEC is a list of key/value pairs, with the keys being lower bounds
+   of a range.  Output a decision tree that handles the keys covered by
+   [VEC[START], VEC[END]), returning FALLBACK for keys lower then VEC[START]'s.
+   INDENT is the number of spaces to indent the code.  */
+static void
+print_type_tree (const vec <std::pair <unsigned int, const char *> > &vec,
+		 unsigned int start, unsigned int end, const char *fallback,
+		 unsigned int indent)
+{
+  while (start < end)
+    {
+      unsigned int mid = (start + end) / 2;
+      printf ("%*sif (c >= CONSTRAINT_%s)\n",
+	      indent, "", enum_order[vec[mid].first]->c_name);
+      if (mid + 1 == end)
+	print_type_tree (vec, mid + 1, end, vec[mid].second, indent + 2);
+      else
+	{
+	  printf ("%*s{\n", indent + 2, "");
+	  print_type_tree (vec, mid + 1, end, vec[mid].second, indent + 4);
+	  printf ("%*s}\n", indent + 2, "");
+	}
+      end = mid;
+    }
+  printf ("%*sreturn %s;\n", indent, "", fallback);
+}
+
 /* Write tm-preds.h.  Unfortunately, it is impossible to forward-declare
    an enumeration in portable C, so we have to condition all these
    prototypes on HAVE_MACHINE_MODES.  */
@@ -1321,21 +1348,13 @@ #define GCC_TM_PREDS_H\n\
 	      "  if (insn_extra_register_constraint (c))\n"
 	      "    return reg_class_for_constraint_1 (c);\n"
 	      "  return NO_REGS;\n"
-	      "}\n"
-	      "\n"
-	      "#define REG_CLASS_FROM_CONSTRAINT(c_,s_) \\\n"
-	      "    reg_class_for_constraint (lookup_constraint (s_))\n"
-	      "#define REG_CLASS_FOR_CONSTRAINT(x_) \\\n"
-	      "    reg_class_for_constraint (x_)\n");
+	      "}\n");
       else
 	puts ("static inline enum reg_class\n"
 	      "reg_class_for_constraint (enum constraint_num)\n"
 	      "{\n"
 	      "  return NO_REGS;\n"
-	      "}\n\n"
-	      "#define REG_CLASS_FROM_CONSTRAINT(c_,s_) NO_REGS\n"
-	      "#define REG_CLASS_FOR_CONSTRAINT(x_) \\\n"
-	      "    NO_REGS\n");
+	      "}\n");
       if (have_const_int_constraints)
 	puts ("extern bool insn_const_int_ok_for_constraint "
 	      "(HOST_WIDE_INT, enum constraint_num);\n"
@@ -1347,19 +1366,27 @@ #define GCC_TM_PREDS_H\n\
 	      "    constraint_satisfied_p (v_, lookup_constraint (s_))\n");
       else
 	puts ("#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(v_,c_,s_) 0\n");
-      if (have_extra_constraints)
-	puts ("#define EXTRA_CONSTRAINT_STR(v_,c_,s_) \\\n"
-	      "    constraint_satisfied_p (v_, lookup_constraint (s_))\n");
-      if (have_memory_constraints)
-	puts ("#define EXTRA_MEMORY_CONSTRAINT(c_,s_) "
-	      "insn_extra_memory_constraint (lookup_constraint (s_))\n");
-      else
-	puts ("#define EXTRA_MEMORY_CONSTRAINT(c_,s_) false\n");
-      if (have_address_constraints)
-	puts ("#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) "
-	      "insn_extra_address_constraint (lookup_constraint (s_))\n");
-      else
-	puts ("#define EXTRA_ADDRESS_CONSTRAINT(c_,s_) false\n");
+
+      puts ("enum constraint_type\n"
+	    "{\n"
+	    "  CT_REGISTER,\n"
+	    "  CT_MEMORY,\n"
+	    "  CT_ADDRESS,\n"
+	    "  CT_FIXED_FORM\n"
+	    "};\n"
+	    "\n"
+	    "static inline enum constraint_type\n"
+	    "get_constraint_type (enum constraint_num c)\n"
+	    "{");
+      auto_vec <std::pair <unsigned int, const char *>, 3> values;
+      if (memory_start != memory_end)
+	values.safe_push (std::make_pair (memory_start, "CT_MEMORY"));
+      if (address_start != address_end)
+	values.safe_push (std::make_pair (address_start, "CT_ADDRESS"));
+      if (address_end != num_constraints)
+	values.safe_push (std::make_pair (address_end, "CT_FIXED_FORM"));
+      print_type_tree (values, 0, values.length (), "CT_REGISTER", 2);
+      puts ("}");
     }
 
   puts ("#endif /* tm-preds.h */");
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/lra-constraints.c	2014-06-05 21:46:37.913140623 +0100
@@ -394,40 +394,38 @@ valid_address_p (struct address_info *ad
   return valid_address_p (ad->mode, *ad->outer, ad->as);
 }
 
-#ifdef EXTRA_CONSTRAINT_STR
 /* Return true if the eliminated form of memory reference OP satisfies
    extra memory constraint CONSTRAINT.  */
 static bool
-satisfies_memory_constraint_p (rtx op, const char *constraint)
+satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
 {
   struct address_info ad;
 
   decompose_mem_address (&ad, op);
   address_eliminator eliminator (&ad);
-  return EXTRA_CONSTRAINT_STR (op, *constraint, constraint);
+  return constraint_satisfied_p (op, constraint);
 }
 
 /* Return true if the eliminated form of address AD satisfies extra
    address constraint CONSTRAINT.  */
 static bool
 satisfies_address_constraint_p (struct address_info *ad,
-				const char *constraint)
+				enum constraint_num constraint)
 {
   address_eliminator eliminator (ad);
-  return EXTRA_CONSTRAINT_STR (*ad->outer, *constraint, constraint);
+  return constraint_satisfied_p (*ad->outer, constraint);
 }
 
 /* Return true if the eliminated form of address OP satisfies extra
    address constraint CONSTRAINT.  */
 static bool
-satisfies_address_constraint_p (rtx op, const char *constraint)
+satisfies_address_constraint_p (rtx op, enum constraint_num constraint)
 {
   struct address_info ad;
 
   decompose_lea_address (&ad, &op);
   return satisfies_address_constraint_p (&ad, constraint);
 }
-#endif
 
 /* Initiate equivalences for LRA.  As we keep original equivalences
    before any elimination, we need to make copies otherwise any change
@@ -982,21 +980,20 @@ reg_class_from_constraints (const char *
 	break;
 
       default:
-	if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+	enum constraint_num cn = lookup_constraint (p);
+	enum reg_class cl = reg_class_for_constraint (cn);
+	if (cl == NO_REGS)
 	  {
-#ifdef EXTRA_CONSTRAINT_STR
-	    if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+	    if (insn_extra_address_constraint (cn))
 	      op_class
 		= (reg_class_subunion
 		   [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
 					      ADDRESS, SCRATCH)]);
-#endif
 	    break;
 	  }
 
-	op_class
-	  = reg_class_subunion[op_class][REG_CLASS_FROM_CONSTRAINT (c, p)];
-	break;
+	op_class = reg_class_subunion[op_class][cl];
+ 	break;
       }
   while ((p += len), c);
   return op_class;
@@ -1712,6 +1709,7 @@ process_alt_operands (int only_alternati
 	  bool this_alternative_offmemok;
 	  bool scratch_p;
 	  enum machine_mode mode;
+	  enum constraint_num cn;
 
 	  opalt_num = nalt * n_operands + nop;
 	  if (curr_static_id->operand_alternative[opalt_num].anything_ok)
@@ -2030,76 +2028,55 @@ process_alt_operands (int only_alternati
 		  /* Drop through into 'r' case.  */
 
 		case 'r':
-		  this_alternative
-		    = reg_class_subunion[this_alternative][GENERAL_REGS];
-		  IOR_HARD_REG_SET (this_alternative_set,
-				    reg_class_contents[GENERAL_REGS]);
-		  if (costly_p)
-		    {
-		      this_costly_alternative
-			= (reg_class_subunion
-			   [this_costly_alternative][GENERAL_REGS]);
-		      IOR_HARD_REG_SET (this_costly_alternative_set,
-					reg_class_contents[GENERAL_REGS]);
-		    }
+		  cl = GENERAL_REGS;
 		  goto reg;
 
 		default:
-		  if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+		  cn = lookup_constraint (p);
+		  switch (get_constraint_type (cn))
 		    {
-#ifdef EXTRA_CONSTRAINT_STR
-		      if (EXTRA_MEMORY_CONSTRAINT (c, p))
-			{
-			  if (MEM_P (op)
-			      && satisfies_memory_constraint_p (op, p))
-			    win = true;
-			  else if (spilled_pseudo_p (op))
-			    win = true;
-
-			  /* If we didn't already win, we can reload
-			     constants via force_const_mem or put the
-			     pseudo value into memory, or make other
-			     memory by reloading the address like for
-			     'o'.  */
-			  if (CONST_POOL_OK_P (mode, op)
-			      || MEM_P (op) || REG_P (op))
-			    badop = false;
-			  constmemok = true;
-			  offmemok = true;
-			  break;
-			}
-		      if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-			{
-			  if (satisfies_address_constraint_p (op, p))
-			    win = true;
+		    case CT_REGISTER:
+		      cl = reg_class_for_constraint (cn);
+		      if (cl != NO_REGS)
+			goto reg;
+		      break;
 
-			  /* If we didn't already win, we can reload
-			     the address into a base register.	*/
-			  cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-					       ADDRESS, SCRATCH);
-			  this_alternative
-			    = reg_class_subunion[this_alternative][cl];
-			  IOR_HARD_REG_SET (this_alternative_set,
-					    reg_class_contents[cl]);
-			  if (costly_p)
-			    {
-			      this_costly_alternative
-				= (reg_class_subunion
-				   [this_costly_alternative][cl]);
-			      IOR_HARD_REG_SET (this_costly_alternative_set,
-						reg_class_contents[cl]);
-			    }
-			  badop = false;
-			  break;
-			}
+		    case CT_MEMORY:
+		      if (MEM_P (op)
+			  && satisfies_memory_constraint_p (op, cn))
+			win = true;
+		      else if (spilled_pseudo_p (op))
+			win = true;
 
-		      if (EXTRA_CONSTRAINT_STR (op, c, p))
+		      /* If we didn't already win, we can reload constants
+			 via force_const_mem or put the pseudo value into
+			 memory, or make other memory by reloading the
+			 address like for 'o'.  */
+		      if (CONST_POOL_OK_P (mode, op)
+			  || MEM_P (op) || REG_P (op))
+			badop = false;
+		      constmemok = true;
+		      offmemok = true;
+		      break;
+
+		    case CT_ADDRESS:
+		      /* If we didn't already win, we can reload the address
+			 into a base register.  */
+		      if (satisfies_address_constraint_p (op, cn))
+			win = true;
+		      cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+					   ADDRESS, SCRATCH);
+		      badop = false;
+		      goto reg;
+
+		    case CT_FIXED_FORM:
+		      if (constraint_satisfied_p (op, cn))
 			win = true;
-#endif
 		      break;
 		    }
+		  break;
 
-		  cl = REG_CLASS_FROM_CONSTRAINT (c, p);
+		reg:
 		  this_alternative = reg_class_subunion[this_alternative][cl];
 		  IOR_HARD_REG_SET (this_alternative_set,
 				    reg_class_contents[cl]);
@@ -2110,7 +2087,6 @@ process_alt_operands (int only_alternati
 		      IOR_HARD_REG_SET (this_costly_alternative_set,
 					reg_class_contents[cl]);
 		    }
-		reg:
 		  if (mode == BLKmode)
 		    break;
 		  winreg = true;
@@ -2856,10 +2832,11 @@ process_address_1 (int nop, rtx *before,
   rtx new_reg;
   rtx op = *curr_id->operand_loc[nop];
   const char *constraint = curr_static_id->operand[nop].constraint;
+  enum constraint_num cn = lookup_constraint (constraint);
   bool change_p;
 
   if (constraint[0] == 'p'
-      || EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint))
+      || insn_extra_address_constraint (cn))
     decompose_lea_address (&ad, curr_id->operand_loc[nop]);
   else if (MEM_P (op))
     decompose_mem_address (&ad, op);
@@ -2888,14 +2865,12 @@ process_address_1 (int nop, rtx *before,
       && process_addr_reg (ad.index_term, before, NULL, INDEX_REG_CLASS))
     change_p = true;
 
-#ifdef EXTRA_CONSTRAINT_STR
-  /* Target hooks sometimes reject extra constraint addresses -- use
-     EXTRA_CONSTRAINT_STR for the validation.  */
+  /* Target hooks sometimes don't treat extra-constraint addresses as
+     legitimate address_operands, so handle them specially.  */
   if (constraint[0] != 'p'
-      && EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint)
-      && satisfies_address_constraint_p (&ad, constraint))
+      && insn_extra_address_constraint (cn)
+      && satisfies_address_constraint_p (&ad, cn))
     return change_p;
-#endif
 
   /* There are three cases where the shape of *AD.INNER may now be invalid:
 
@@ -3610,11 +3585,10 @@ curr_insn_transform (void)
 	      {
 		if (c == TARGET_MEM_CONSTRAINT || c == 'o')
 		  break;
-#ifdef EXTRA_CONSTRAINT_STR
-		if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
-		    && satisfies_memory_constraint_p (tem, constraint))
+		enum constraint_num cn = lookup_constraint (constraint);
+		if (insn_extra_memory_constraint (cn)
+		    && satisfies_memory_constraint_p (tem, cn))
 		  break;
-#endif
 	      }
 	    if (c == '\0' || c == ',' || c == '#')
 	      continue;
Index: gcc/ira-costs.c
===================================================================
--- gcc/ira-costs.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/ira-costs.c	2014-06-05 21:45:00.208282750 +0100
@@ -753,25 +753,28 @@ record_reg_classes (int n_alts, int n_op
 		  break;
 
 		default:
-		  if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS)
-		    classes[i] = ira_reg_class_subunion[classes[i]]
-		                 [REG_CLASS_FROM_CONSTRAINT (c, p)];
-#ifdef EXTRA_CONSTRAINT_STR
-		  else if (EXTRA_CONSTRAINT_STR (op, c, p))
-		    win = 1;
-
-		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
+		  enum constraint_num cn = lookup_constraint (p);
+		  enum reg_class cl;
+		  switch (get_constraint_type (cn))
 		    {
+		    case CT_REGISTER:
+		      cl = reg_class_for_constraint (cn);
+		      if (cl != NO_REGS)
+			classes[i] = ira_reg_class_subunion[classes[i]][cl];
+		      break;
+
+		    case CT_MEMORY:
 		      /* Every MEM can be reloaded to fit.  */
 		      insn_allows_mem[i] = allows_mem[i] = 1;
 		      if (MEM_P (op))
 			win = 1;
-		    }
-		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-		    {
+		      break;
+
+		    case CT_ADDRESS:
 		      /* Every address can be reloaded to fit.  */
 		      allows_addr = 1;
-		      if (address_operand (op, GET_MODE (op)))
+		      if (address_operand (op, GET_MODE (op))
+			  || constraint_satisfied_p (op, cn))
 			win = 1;
 		      /* We know this operand is an address, so we
 			 want it to be allocated to a hard register
@@ -781,8 +784,13 @@ record_reg_classes (int n_alts, int n_op
 			= ira_reg_class_subunion[classes[i]]
 			  [base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
 					   ADDRESS, SCRATCH)];
+		      break;
+
+		    case CT_FIXED_FORM:
+		      if (constraint_satisfied_p (op, cn))
+			win = 1;
+		      break;
 		    }
-#endif
 		  break;
 		}
 	      p += CONSTRAINT_LEN (c, p);
@@ -1275,8 +1283,8 @@ record_operand_costs (rtx insn, enum reg
 			     XEXP (recog_data.operand[i], 0),
 			     0, MEM, SCRATCH, frequency * 2);
       else if (constraints[i][0] == 'p'
-	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0],
-					    constraints[i]))
+	       || (insn_extra_address_constraint
+		   (lookup_constraint (constraints[i]))))
 	record_address_regs (VOIDmode, ADDR_SPACE_GENERIC,
 			     recog_data.operand[i], 0, ADDRESS, SCRATCH,
 			     frequency * 2);
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	2014-06-05 21:45:00.132282083 +0100
+++ gcc/ira-lives.c	2014-06-05 21:45:00.212282786 +0100
@@ -759,6 +759,7 @@ single_reg_class (const char *constraint
 {
   int c;
   enum reg_class cl, next_cl;
+  enum constraint_num cn;
 
   cl = NO_REGS;
   alternative_mask enabled = recog_data.enabled_alternatives;
@@ -849,20 +850,19 @@ single_reg_class (const char *constraint
 	case 'A': case 'B': case 'C': case 'D':
 	case 'Q': case 'R': case 'S': case 'T': case 'U':
 	case 'W': case 'Y': case 'Z':
-#ifdef EXTRA_CONSTRAINT_STR
 	  /* ??? Is this the best way to handle memory constraints?  */
-	  if (EXTRA_MEMORY_CONSTRAINT (c, constraints)
-	      || EXTRA_ADDRESS_CONSTRAINT (c, constraints))
+	  cn = lookup_constraint (constraints);
+	  if (insn_extra_memory_constraint (cn)
+	      || insn_extra_address_constraint (cn))
 	    return NO_REGS;
-	  if (EXTRA_CONSTRAINT_STR (op, c, constraints)
+	  if (constraint_satisfied_p (op, cn)
 	      || (equiv_const != NULL_RTX
 		  && CONSTANT_P (equiv_const)
-		  && EXTRA_CONSTRAINT_STR (equiv_const, c, constraints)))
+		  && constraint_satisfied_p (equiv_const, cn)))
 	    return NO_REGS;
-#endif
 	  next_cl = (c == 'r'
 		     ? GENERAL_REGS
-		     : REG_CLASS_FROM_CONSTRAINT (c, constraints));
+		     : reg_class_for_constraint (cn));
 	  if (next_cl == NO_REGS)
 	    break;
 	  if (cl == NO_REGS
@@ -950,7 +950,7 @@ ira_implicitly_set_insn_hard_regs (HARD_
 		case 'W': case 'Y': case 'Z':
 		  cl = (c == 'r'
 			? GENERAL_REGS
-			: REG_CLASS_FROM_CONSTRAINT (c, p));
+			: reg_class_for_constraint (lookup_constraint (p)));
 		  if (cl != NO_REGS)
 		    {
 		      /* There is no register pressure problem if all of the
Index: gcc/ira.c
===================================================================
--- gcc/ira.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/ira.c	2014-06-05 21:45:00.204282715 +0100
@@ -1922,24 +1922,29 @@ ira_setup_alts (rtx insn, HARD_REG_SET &
 		    break;
 		    
 		  case 'o':
+		  case 'r':
 		    goto op_success;
 		    break;
 		    
 		  default:
 		    {
-		      enum reg_class cl;
-		      
-		      cl = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
-		      if (cl != NO_REGS)
-			goto op_success;
-#ifdef EXTRA_CONSTRAINT_STR
-		      else if (EXTRA_CONSTRAINT_STR (op, c, p))
-			goto op_success;
-		      else if (EXTRA_MEMORY_CONSTRAINT (c, p))
-			goto op_success;
-		      else if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-			goto op_success;
-#endif
+		      enum constraint_num cn = lookup_constraint (p);
+		      switch (get_constraint_type (cn))
+			{
+			case CT_REGISTER:
+			  if (reg_class_for_constraint (cn) != NO_REGS)
+			    goto op_success;
+			  break;
+
+			case CT_ADDRESS:
+			case CT_MEMORY:
+			  goto op_success;
+
+			case CT_FIXED_FORM:
+			  if (constraint_satisfied_p (op, cn))
+			    goto op_success;
+			  break;
+			}
 		      break;
 		    }
 		  }
@@ -1972,9 +1977,6 @@ ira_get_dup_out_num (int op_num, HARD_RE
   int curr_alt, c, original, dup;
   bool ignore_p, use_commut_op_p;
   const char *str;
-#ifdef EXTRA_CONSTRAINT_STR
-  rtx op;
-#endif
 
   if (op_num < 0 || recog_data.n_alternatives == 0)
     return -1;
@@ -1985,9 +1987,7 @@ ira_get_dup_out_num (int op_num, HARD_RE
   use_commut_op_p = false;
   for (;;)
     {
-#ifdef EXTRA_CONSTRAINT_STR
-      op = recog_data.operand[op_num];
-#endif
+      rtx op = recog_data.operand[op_num];
       
       for (curr_alt = 0, ignore_p = !TEST_HARD_REG_BIT (alts, curr_alt),
 	   original = -1;;)
@@ -2010,6 +2010,9 @@ ira_get_dup_out_num (int op_num, HARD_RE
 	      case 'g':
 		goto fail;
 	      case 'r':
+		if (!targetm.class_likely_spilled_p (GENERAL_REGS))
+		  goto fail;
+		break;
 	      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
 	      case 'h': case 'j': case 'k': case 'l':
 	      case 'q': case 't': case 'u':
@@ -2018,19 +2021,13 @@ ira_get_dup_out_num (int op_num, HARD_RE
 	      case 'Q': case 'R': case 'S': case 'T': case 'U':
 	      case 'W': case 'Y': case 'Z':
 		{
-		  enum reg_class cl;
-		  
-		  cl = (c == 'r'
-			? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, str));
-		  if (cl != NO_REGS)
-		    {
-		      if (! targetm.class_likely_spilled_p (cl))
-			goto fail;
-		    }
-#ifdef EXTRA_CONSTRAINT_STR
-		  else if (EXTRA_CONSTRAINT_STR (op, c, str))
+		  enum constraint_num cn = lookup_constraint (str);
+		  enum reg_class cl = reg_class_for_constraint (cn);
+		  if (cl != NO_REGS
+		      && !targetm.class_likely_spilled_p (cl))
+		    goto fail;
+		  if (constraint_satisfied_p (op, cn))
 		    goto fail;
-#endif
 		  break;
 		}
 		
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/postreload.c	2014-06-05 21:45:00.220282856 +0100
@@ -574,8 +574,8 @@ reload_cse_simplify_operands (rtx insn,
 		default:
 		  rclass
 		    = (reg_class_subunion
-		       [(int) rclass]
-		       [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
+		       [rclass]
+		       [reg_class_for_constraint (lookup_constraint (p))]);
 		  break;
 
 		case ',': case '\0':
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/recog.c	2014-06-05 21:45:00.209282759 +0100
@@ -1729,6 +1729,7 @@ asm_operand_ok (rtx op, const char *cons
 
   while (*constraint)
     {
+      enum constraint_num cn;
       char c = *constraint;
       int len;
       switch (c)
@@ -1902,27 +1903,37 @@ asm_operand_ok (rtx op, const char *cons
 	    result = 1;
 	  break;
 
+	case 'r':
+	reg:
+	  if (!result
+	      && GET_MODE (op) != BLKmode
+	      && register_operand (op, VOIDmode))
+	    result = 1;
+	  break;
+
 	default:
-	  /* For all other letters, we first check for a register class,
-	     otherwise it is an EXTRA_CONSTRAINT.  */
-	  if (REG_CLASS_FROM_CONSTRAINT (c, constraint) != NO_REGS)
+	  cn = lookup_constraint (constraint);
+	  switch (get_constraint_type (cn))
 	    {
-	    case 'r':
-	      if (GET_MODE (op) == BLKmode)
-		break;
-	      if (register_operand (op, VOIDmode))
-		result = 1;
+	    case CT_REGISTER:
+	      if (reg_class_for_constraint (cn) != NO_REGS)
+		goto reg;
+	      break;
+
+	    case CT_MEMORY:
+	      /* Every memory operand can be reloaded to fit.  */
+	      result = result || memory_operand (op, VOIDmode);
+	      break;
+
+	    case CT_ADDRESS:
+	      /* Every address operand can be reloaded to fit.  */
+	      result = result || address_operand (op, VOIDmode);
+	      break;
+
+	    case CT_FIXED_FORM:
+	      result = result || constraint_satisfied_p (op, cn);
+	      break;
 	    }
-#ifdef EXTRA_CONSTRAINT_STR
-	  else if (EXTRA_MEMORY_CONSTRAINT (c, constraint))
-	    /* Every memory operand can be reloaded to fit.  */
-	    result = result || memory_operand (op, VOIDmode);
-	  else if (EXTRA_ADDRESS_CONSTRAINT (c, constraint))
-	    /* Every address operand can be reloaded to fit.  */
-	    result = result || address_operand (op, VOIDmode);
-	  else if (EXTRA_CONSTRAINT_STR (op, c, constraint))
-	    result = 1;
-#endif
 	  break;
 	}
       len = CONSTRAINT_LEN (c, constraint);
@@ -2434,13 +2445,21 @@ preprocess_constraints (int n_operands,
 		  break;
 
 		default:
-		  if (EXTRA_MEMORY_CONSTRAINT (c, p))
+		  enum constraint_num cn = lookup_constraint (p);
+		  enum reg_class cl;
+		  switch (get_constraint_type (cn))
 		    {
+		    case CT_REGISTER:
+		      cl = reg_class_for_constraint (cn);
+		      if (cl != NO_REGS)
+			op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl];
+		      break;
+
+		    case CT_MEMORY:
 		      op_alt[i].memory_ok = 1;
 		      break;
-		    }
-		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-		    {
+
+		    case CT_ADDRESS:
 		      op_alt[i].is_address = 1;
 		      op_alt[i].cl
 			= (reg_class_subunion
@@ -2448,12 +2467,10 @@ preprocess_constraints (int n_operands,
 			   [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
 						  ADDRESS, SCRATCH)]);
 		      break;
-		    }
 
-		  op_alt[i].cl
-		    = (reg_class_subunion
-		       [(int) op_alt[i].cl]
-		       [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
+		    case CT_FIXED_FORM:
+		      break;
+		    }
 		  break;
 		}
 	      p += CONSTRAINT_LEN (c, p);
@@ -2846,9 +2863,12 @@ constrain_operands (int strict)
 	      default:
 		{
 		  enum reg_class cl;
+		  enum constraint_num cn = (c == 'r'
+					    ? CONSTRAINT__UNKNOWN
+					    : lookup_constraint (p));
 
 		  cl = (c == 'r'
-			   ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
+			? GENERAL_REGS : reg_class_for_constraint (cn));
 		  if (cl != NO_REGS)
 		    {
 		      if (strict < 0
@@ -2860,11 +2880,11 @@ constrain_operands (int strict)
 			      && reg_fits_class_p (op, cl, offset, mode)))
 		        win = 1;
 		    }
-#ifdef EXTRA_CONSTRAINT_STR
-		  else if (EXTRA_CONSTRAINT_STR (op, c, p))
+
+		  else if (constraint_satisfied_p (op, cn))
 		    win = 1;
 
-		  else if (EXTRA_MEMORY_CONSTRAINT (c, p)
+		  else if (insn_extra_memory_constraint (cn)
 			   /* Every memory operand can be reloaded to fit.  */
 			   && ((strict < 0 && MEM_P (op))
 			       /* Before reload, accept what reload can turn
@@ -2874,7 +2894,7 @@ constrain_operands (int strict)
 			       || (reload_in_progress && REG_P (op)
 				   && REGNO (op) >= FIRST_PSEUDO_REGISTER)))
 		    win = 1;
-		  else if (EXTRA_ADDRESS_CONSTRAINT (c, p)
+		  else if (insn_extra_address_constraint (cn)
 			   /* Every address operand can be reloaded to fit.  */
 			   && strict < 0)
 		    win = 1;
@@ -2885,10 +2905,9 @@ constrain_operands (int strict)
 			   && REGNO (op) >= FIRST_PSEUDO_REGISTER
 			   && reg_renumber[REGNO (op)] < 0
 			   && reg_equiv_mem (REGNO (op)) != 0
-			   && EXTRA_CONSTRAINT_STR
-			      (reg_equiv_mem (REGNO (op)), c, p))
+			   && constraint_satisfied_p
+			      (reg_equiv_mem (REGNO (op)), cn))
 		    win = 1;
-#endif
 		  break;
 		}
 	      }
@@ -3283,7 +3302,7 @@ peep2_find_free_register (int from, int
     }
 
   cl = (class_str[0] == 'r' ? GENERAL_REGS
-	   : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
+	: reg_class_for_constraint (lookup_constraint (class_str)));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/reload.c	2014-06-05 21:45:00.214282803 +0100
@@ -401,8 +401,8 @@ push_secondary_reload (int in_p, rtx x,
 	scratch_constraint++;
       letter = *scratch_constraint;
       scratch_class = (letter == 'r' ? GENERAL_REGS
-		       : REG_CLASS_FROM_CONSTRAINT ((unsigned char) letter,
-						   scratch_constraint));
+		       : (reg_class_for_constraint
+			  (lookup_constraint (scratch_constraint))));
 
       rclass = scratch_class;
       mode = insn_data[(int) icode].operand[2].mode;
@@ -560,8 +560,7 @@ scratch_reload_class (enum insn_code ico
   scratch_letter = *scratch_constraint;
   if (scratch_letter == 'r')
     return GENERAL_REGS;
-  rclass = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
-				     scratch_constraint);
+  rclass = reg_class_for_constraint (lookup_constraint (scratch_constraint));
   gcc_assert (rclass != NO_REGS);
   return rclass;
 }
@@ -2852,7 +2851,8 @@ find_reloads (rtx insn, int replace, int
 	/* Ignore things like match_operator operands.  */
 	;
       else if (constraints[i][0] == 'p'
-	       || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
+	       || (insn_extra_address_constraint
+		   (lookup_constraint (constraints[i]))))
 	{
 	  address_operand_reloaded[i]
 	    = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
@@ -3094,6 +3094,8 @@ find_reloads (rtx insn, int replace, int
 		 operand.  */
 	      int constmemok = 0;
 	      int earlyclobber = 0;
+	      enum constraint_num cn;
+	      enum reg_class cl;
 
 	      /* If the predicate accepts a unary operator, it means that
 		 we need to reload the operand, but do not do this for
@@ -3489,71 +3491,74 @@ find_reloads (rtx insn, int replace, int
 		    /* Drop through into 'r' case.  */
 
 		  case 'r':
-		    this_alternative[i]
-		      = reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
+		    cl = GENERAL_REGS;
 		    goto reg;
 
 		  default:
-		    if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+		    cn = lookup_constraint (p);
+		    switch (get_constraint_type (cn))
 		      {
-#ifdef EXTRA_CONSTRAINT_STR
-			if (EXTRA_MEMORY_CONSTRAINT (c, p))
-			  {
-			    if (force_reload)
-			      break;
-			    if (EXTRA_CONSTRAINT_STR (operand, c, p))
-			      win = 1;
-			    /* If the address was already reloaded,
-			       we win as well.  */
-			    else if (MEM_P (operand)
-				     && address_reloaded[i] == 1)
-			      win = 1;
-			    /* Likewise if the address will be reloaded because
-			       reg_equiv_address is nonzero.  For reg_equiv_mem
-			       we have to check.  */
-			    else if (REG_P (operand)
-				     && REGNO (operand) >= FIRST_PSEUDO_REGISTER
-				     && reg_renumber[REGNO (operand)] < 0
-				     && ((reg_equiv_mem (REGNO (operand)) != 0
-					  && EXTRA_CONSTRAINT_STR (reg_equiv_mem (REGNO (operand)), c, p))
-					 || (reg_equiv_address (REGNO (operand)) != 0)))
-			      win = 1;
-
-			    /* If we didn't already win, we can reload
-			       constants via force_const_mem, and other
-			       MEMs by reloading the address like for 'o'.  */
-			    if (CONST_POOL_OK_P (operand_mode[i], operand)
-				|| MEM_P (operand))
-			      badop = 0;
-			    constmemok = 1;
-			    offmemok = 1;
-			    break;
-			  }
-			if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-			  {
-			    if (EXTRA_CONSTRAINT_STR (operand, c, p))
-			      win = 1;
+		      case CT_REGISTER:
+			cl = reg_class_for_constraint (cn);
+			if (cl != NO_REGS)
+			  goto reg;
+			break;
 
-			    /* If we didn't already win, we can reload
-			       the address into a base register.  */
-			    this_alternative[i]
-			      = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-						ADDRESS, SCRATCH);
-			    badop = 0;
-			    break;
-			  }
+		      case CT_MEMORY:
+			if (force_reload)
+			  break;
+			if (constraint_satisfied_p (operand, cn))
+			  win = 1;
+			/* If the address was already reloaded,
+			   we win as well.  */
+			else if (MEM_P (operand) && address_reloaded[i] == 1)
+			  win = 1;
+			/* Likewise if the address will be reloaded because
+			   reg_equiv_address is nonzero.  For reg_equiv_mem
+			   we have to check.  */
+			else if (REG_P (operand)
+				 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+				 && reg_renumber[REGNO (operand)] < 0
+				 && ((reg_equiv_mem (REGNO (operand)) != 0
+				      && (constraint_satisfied_p
+					  (reg_equiv_mem (REGNO (operand)),
+					   cn)))
+				     || (reg_equiv_address (REGNO (operand))
+					 != 0)))
+			  win = 1;
 
-			if (EXTRA_CONSTRAINT_STR (operand, c, p))
+			/* If we didn't already win, we can reload
+			   constants via force_const_mem, and other
+			   MEMs by reloading the address like for 'o'.  */
+			if (CONST_POOL_OK_P (operand_mode[i], operand)
+			    || MEM_P (operand))
+			  badop = 0;
+			constmemok = 1;
+			offmemok = 1;
+			break;
+
+		      case CT_ADDRESS:
+			if (constraint_satisfied_p (operand, cn))
+			  win = 1;
+
+			/* If we didn't already win, we can reload
+			   the address into a base register.  */
+			this_alternative[i]
+			  = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+					    ADDRESS, SCRATCH);
+			badop = 0;
+			break;
+
+		      case CT_FIXED_FORM:
+			if (constraint_satisfied_p (operand, cn))
 			  win = 1;
-#endif
 			break;
 		      }
+		    break;
 
-		    this_alternative[i]
-		      = (reg_class_subunion
-			 [this_alternative[i]]
-			 [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
 		  reg:
+		    this_alternative[i]
+		      = reg_class_subunion[this_alternative[i]][cl];
 		    if (GET_MODE (operand) == BLKmode)
 		      break;
 		    winreg = 1;
@@ -4687,11 +4692,10 @@ alternative_allows_const_pool_ref (rtx m
     {
       if (c == TARGET_MEM_CONSTRAINT || c == 'o')
 	return true;
-#ifdef EXTRA_CONSTRAINT_STR
-      if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
-	  && (mem == NULL || EXTRA_CONSTRAINT_STR (mem, c, constraint)))
+      enum constraint_num cn = lookup_constraint (constraint);
+      if (insn_extra_memory_constraint (cn)
+	  && (mem == NULL || constraint_satisfied_p (mem, cn)))
 	return true;
-#endif
     }
   return false;
 }
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/reload1.c	2014-06-05 21:45:00.217282830 +0100
@@ -1437,13 +1437,15 @@ maybe_fix_stack_asms (void)
 		  break;
 
 		default:
-		  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+		  enum constraint_num cn = lookup_constraint (p);
+		  if (insn_extra_address_constraint (cn))
 		    cls = (int) reg_class_subunion[cls]
 		      [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
 					     ADDRESS, SCRATCH)];
 		  else
 		    cls = (int) reg_class_subunion[cls]
-		      [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
+		      [reg_class_for_constraint (cn)];
+		  break;
 		}
 	      p += CONSTRAINT_LEN (c, p);
 	    }
Index: gcc/stmt.c
===================================================================
--- gcc/stmt.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/stmt.c	2014-06-05 21:45:00.210282768 +0100
@@ -322,12 +322,11 @@ parse_output_constraint (const char **co
       default:
 	if (!ISALPHA (*p))
 	  break;
-	if (REG_CLASS_FROM_CONSTRAINT (*p, p) != NO_REGS)
+	enum constraint_num cn = lookup_constraint (p);
+	if (reg_class_for_constraint (cn) != NO_REGS
+	    || insn_extra_address_constraint (cn))
 	  *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT_STR
-	else if (EXTRA_ADDRESS_CONSTRAINT (*p, p))
-	  *allows_reg = true;
-	else if (EXTRA_MEMORY_CONSTRAINT (*p, p))
+	else if (insn_extra_memory_constraint (cn))
 	  *allows_mem = true;
 	else
 	  {
@@ -337,7 +336,6 @@ parse_output_constraint (const char **co
 	    *allows_reg = true;
 	    *allows_mem = true;
 	  }
-#endif
 	break;
       }
 
@@ -454,13 +452,11 @@ parse_input_constraint (const char **con
 	    error ("invalid punctuation %qc in constraint", constraint[j]);
 	    return false;
 	  }
-	if (REG_CLASS_FROM_CONSTRAINT (constraint[j], constraint + j)
-	    != NO_REGS)
-	  *allows_reg = true;
-#ifdef EXTRA_CONSTRAINT_STR
-	else if (EXTRA_ADDRESS_CONSTRAINT (constraint[j], constraint + j))
+	enum constraint_num cn = lookup_constraint (constraint + j);
+	if (reg_class_for_constraint (cn) != NO_REGS
+	    || insn_extra_address_constraint (cn))
 	  *allows_reg = true;
-	else if (EXTRA_MEMORY_CONSTRAINT (constraint[j], constraint + j))
+	else if (insn_extra_memory_constraint (cn))
 	  *allows_mem = true;
 	else
 	  {
@@ -470,7 +466,6 @@ parse_input_constraint (const char **con
 	    *allows_reg = true;
 	    *allows_mem = true;
 	  }
-#endif
 	break;
       }
 
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/targhooks.c	2014-06-05 21:45:00.217282830 +0100
@@ -936,8 +936,8 @@ default_secondary_reload (bool in_p ATTR
 	      insn_letter = *insn_constraint;
 	      insn_class
 		= (insn_letter == 'r' ? GENERAL_REGS
-		   : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
-						insn_constraint));
+		   : (reg_class_for_constraint
+		      (lookup_constraint (insn_constraint))));
 	      gcc_assert (insn_class != NO_REGS);
 	    }
 
@@ -954,8 +954,8 @@ default_secondary_reload (bool in_p ATTR
 	  scratch_letter = *scratch_constraint;
 	  scratch_class
 	    = (scratch_letter == 'r' ? GENERAL_REGS
-	       : REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
-					    scratch_constraint));
+	       : (reg_class_for_constraint
+		  (lookup_constraint (scratch_constraint))));
 
 	  if (reg_class_subset_p (reload_class, insn_class))
 	    {
Index: gcc/config/m32c/m32c.c
===================================================================
--- gcc/config/m32c/m32c.c	2014-06-05 21:06:52.721540056 +0100
+++ gcc/config/m32c/m32c.c	2014-06-05 21:45:00.219282847 +0100
@@ -854,7 +854,7 @@ #define IS_PSEUDO(rtx,strict) (!strict &
 
 #define A0_OR_PSEUDO(x) (IS_REG(x, A0_REGNO) || REGNO (x) >= FIRST_PSEUDO_REGISTER)
 
-/* Implements EXTRA_CONSTRAINT_STR (see next function too).  'S' is
+/* Implements matching for constraints (see next function too).  'S' is
    for memory constraints, plus "Rpa" for PARALLEL rtx's we use for
    call return values.  */
 bool
Index: gcc/config/sparc/constraints.md
===================================================================
--- gcc/config/sparc/constraints.md	2014-06-05 21:06:52.721540056 +0100
+++ gcc/config/sparc/constraints.md	2014-06-05 21:45:00.220282856 +0100
@@ -171,7 +171,7 @@ (define_memory_constraint "T"
 ;; define_register_constraint would.  This currently means that we cannot
 ;; use LRA on Sparc, since the constraint processing of LRA really depends
 ;; upon whether an extra constraint is for registers or not.  It uses
-;; REG_CLASS_FROM_CONSTRAINT, and checks it against NO_REGS.
+;; reg_class_for_constraint, and checks it against NO_REGS.
 (define_constraint "U"
  "Pseudo-register or hard even-numbered integer register"
  (and (match_test "TARGET_ARCH32")

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 5/8] Remove unused operand_alternative fields
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
                   ` (3 preceding siblings ...)
  2014-06-05 21:32 ` [PATCH 4/8] Remove old macros and make lookup_constraint explicit Richard Sandiford
@ 2014-06-05 21:33 ` Richard Sandiford
  2014-06-10 18:43   ` Jeff Law
  2014-06-05 21:38 ` [PATCH 6/8] Treat 'I'-'P' as separate subtype Richard Sandiford
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:33 UTC (permalink / raw)
  To: gcc-patches

This patch just gets rid of some write-only operand_alternative fields,
which makes things easier for the later patches to preprocess_constraints.

Richard


gcc/
	* recog.h (operand_alternative): Remove offmem_ok, nonffmem_ok,
	decmem_ok and incmem_ok.  Reformat other bitfields for consistency.
	* recog.c (preprocess_constraints): Update accordingly.

Index: gcc/recog.h
===================================================================
--- gcc/recog.h	2014-06-04 18:15:06.589969020 +0100
+++ gcc/recog.h	2014-06-04 18:19:30.391331977 +0100
@@ -60,25 +60,17 @@ struct operand_alternative
   int matched : 8;
 
   /* Nonzero if '&' was found in the constraint string.  */
-  unsigned int earlyclobber:1;
+  unsigned int earlyclobber : 1;
   /* Nonzero if TARGET_MEM_CONSTRAINT was found in the constraint
      string.  */
-  unsigned int memory_ok:1;
-  /* Nonzero if 'o' was found in the constraint string.  */
-  unsigned int offmem_ok:1;
-  /* Nonzero if 'V' was found in the constraint string.  */
-  unsigned int nonoffmem_ok:1;
-  /* Nonzero if '<' was found in the constraint string.  */
-  unsigned int decmem_ok:1;
-  /* Nonzero if '>' was found in the constraint string.  */
-  unsigned int incmem_ok:1;
+  unsigned int memory_ok : 1;
   /* Nonzero if 'p' was found in the constraint string.  */
-  unsigned int is_address:1;
+  unsigned int is_address : 1;
   /* Nonzero if 'X' was found in the constraint string, or if the constraint
      string for this alternative was empty.  */
-  unsigned int anything_ok:1;
+  unsigned int anything_ok : 1;
 
-  unsigned int unused : 8;
+  unsigned int unused : 12;
 };
 
 /* Return the class for operand I of alternative ALT, taking matching
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	2014-06-04 18:15:06.589969020 +0100
+++ gcc/recog.c	2014-06-04 18:19:30.392331986 +0100
@@ -2415,18 +2415,6 @@ preprocess_constraints (int n_operands,
 		case TARGET_MEM_CONSTRAINT:
 		  op_alt[i].memory_ok = 1;
 		  break;
-		case '<':
-		  op_alt[i].decmem_ok = 1;
-		  break;
-		case '>':
-		  op_alt[i].incmem_ok = 1;
-		  break;
-		case 'V':
-		  op_alt[i].nonoffmem_ok = 1;
-		  break;
-		case 'o':
-		  op_alt[i].offmem_ok = 1;
-		  break;
 		case 'X':
 		  op_alt[i].anything_ok = 1;
 		  break;

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 6/8] Treat 'I'-'P' as separate subtype
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
                   ` (4 preceding siblings ...)
  2014-06-05 21:33 ` [PATCH 5/8] Remove unused operand_alternative fields Richard Sandiford
@ 2014-06-05 21:38 ` Richard Sandiford
  2014-06-10 18:48   ` Jeff Law
  2014-06-05 21:41 ` [PATCH 7/8] Remove 'I'-'P' and 'G'/'H' cases Richard Sandiford
  2014-06-05 21:43 ` [PATCH 8/8] Add a common .md file and define standard constraints there Richard Sandiford
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:38 UTC (permalink / raw)
  To: gcc-patches

This patch extends patch 4 to have a CT_CONST_INT type for CONST_INT
constraints ('I'-'P'), which are already handled by things like
constraint_satisfied_p.  On its own this has little effect, since most
places handle 'I'-'P' as a separate case statement anyway.  It's really
just making way for the final patch.

It might be worth adding a define_const_int_constraint so that 'I'-'P'
are less special.

Richard


gcc/
	* genpreds.c (const_int_start, const_int_end): New variables.
	(choose_enum_order): Output CONST_INT constraints before memory
	constraints.
	(write_tm_preds_h): Always define insn_const_int_ok_for_constraint.
	Add CT_CONST_INT.
	* ira-costs.c (record_reg_classes): Handle CT_CONST_INT.
	* ira.c (ira_setup_alts): Likewise.
	* lra-constraints.c (process_alt_operands): Likewise.
	* recog.c (asm_operand_ok, preprocess_constraints): Likewise.
	* reload.c (find_reloads): Likewise.

Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-04 18:46:18.253815502 +0100
+++ gcc/genpreds.c	2014-06-04 18:57:19.968858594 +0100
@@ -690,6 +690,7 @@ static const char const_dbl_constraints[
 static const constraint_data **enum_order;
 static unsigned int register_start, register_end;
 static unsigned int satisfied_start;
+static unsigned int const_int_start, const_int_end;
 static unsigned int memory_start, memory_end;
 static unsigned int address_start, address_end;
 
@@ -931,6 +932,12 @@ choose_enum_order (void)
 
   satisfied_start = next;
 
+  const_int_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (c->is_const_int)
+      enum_order[next++] = c;
+  const_int_end = next;
+
   memory_start = next;
   FOR_ALL_CONSTRAINTS (c)
     if (c->is_memory)
@@ -944,7 +951,7 @@ choose_enum_order (void)
   address_end = next;
 
   FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register && !c->is_memory && !c->is_address)
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address)
       enum_order[next++] = c;
   gcc_assert (next == num_constraints);
 }
@@ -1361,6 +1368,13 @@ #define GCC_TM_PREDS_H\n\
 	      "#define CONST_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n"
 	      "    insn_const_int_ok_for_constraint (v_, "
 	      "lookup_constraint (s_))\n");
+      else
+	puts ("static inline bool\n"
+	      "insn_const_int_ok_for_constraint (HOST_WIDE_INT,"
+	      " enum constraint_num)\n"
+	      "{\n"
+	      "  return false;\n"
+	      "}\n");
       if (have_const_dbl_constraints)
 	puts ("#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n"
 	      "    constraint_satisfied_p (v_, lookup_constraint (s_))\n");
@@ -1370,6 +1384,7 @@ #define GCC_TM_PREDS_H\n\
       puts ("enum constraint_type\n"
 	    "{\n"
 	    "  CT_REGISTER,\n"
+	    "  CT_CONST_INT,\n"
 	    "  CT_MEMORY,\n"
 	    "  CT_ADDRESS,\n"
 	    "  CT_FIXED_FORM\n"
@@ -1378,7 +1393,9 @@ #define GCC_TM_PREDS_H\n\
 	    "static inline enum constraint_type\n"
 	    "get_constraint_type (enum constraint_num c)\n"
 	    "{");
-      auto_vec <std::pair <unsigned int, const char *>, 3> values;
+      auto_vec <std::pair <unsigned int, const char *>, 4> values;
+      if (const_int_start != const_int_end)
+	values.safe_push (std::make_pair (const_int_start, "CT_CONST_INT"));
       if (memory_start != memory_end)
 	values.safe_push (std::make_pair (memory_start, "CT_MEMORY"));
       if (address_start != address_end)
Index: gcc/ira-costs.c
===================================================================
--- gcc/ira-costs.c	2014-06-04 18:46:18.250815475 +0100
+++ gcc/ira-costs.c	2014-06-04 18:57:19.969858603 +0100
@@ -763,6 +763,12 @@ record_reg_classes (int n_alts, int n_op
 			classes[i] = ira_reg_class_subunion[classes[i]][cl];
 		      break;
 
+		    case CT_CONST_INT:
+		      if (CONST_INT_P (op)
+			  && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+			win = 1;
+		      break;
+
 		    case CT_MEMORY:
 		      /* Every MEM can be reloaded to fit.  */
 		      insn_allows_mem[i] = allows_mem[i] = 1;
Index: gcc/ira.c
===================================================================
--- gcc/ira.c	2014-06-04 18:46:18.245815430 +0100
+++ gcc/ira.c	2014-06-04 18:57:19.971858622 +0100
@@ -1936,6 +1936,13 @@ ira_setup_alts (rtx insn, HARD_REG_SET &
 			    goto op_success;
 			  break;
 
+			case CT_CONST_INT:
+			  if (CONST_INT_P (op)
+			      && (insn_const_int_ok_for_constraint
+				  (INTVAL (op), cn)))
+			    goto op_success;
+			  break;
+
 			case CT_ADDRESS:
 			case CT_MEMORY:
 			  goto op_success;
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2014-06-04 18:52:10.976036815 +0100
+++ gcc/lra-constraints.c	2014-06-04 18:57:19.973858640 +0100
@@ -2041,6 +2041,12 @@ process_alt_operands (int only_alternati
 			goto reg;
 		      break;
 
+		    case CT_CONST_INT:
+		      if (CONST_INT_P (op)
+			  && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+			win = true;
+		      break;
+
 		    case CT_MEMORY:
 		      if (MEM_P (op)
 			  && satisfies_memory_constraint_p (op, cn))
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	2014-06-04 18:57:18.145841967 +0100
+++ gcc/recog.c	2014-06-04 18:57:19.975858658 +0100
@@ -1920,6 +1920,13 @@ asm_operand_ok (rtx op, const char *cons
 		goto reg;
 	      break;
 
+	    case CT_CONST_INT:
+	      if (!result
+		  && CONST_INT_P (op)
+		  && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+		result = 1;
+	      break;
+
 	    case CT_MEMORY:
 	      /* Every memory operand can be reloaded to fit.  */
 	      result = result || memory_operand (op, VOIDmode);
@@ -2443,6 +2450,9 @@ preprocess_constraints (int n_operands,
 			op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl];
 		      break;
 
+		    case CT_CONST_INT:
+		      break;
+
 		    case CT_MEMORY:
 		      op_alt[i].memory_ok = 1;
 		      break;
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2014-06-04 18:46:18.256815529 +0100
+++ gcc/reload.c	2014-06-04 18:57:19.977858677 +0100
@@ -3504,6 +3504,13 @@ find_reloads (rtx insn, int replace, int
 			  goto reg;
 			break;
 
+		      case CT_CONST_INT:
+			if (CONST_INT_P (operand)
+			    && (insn_const_int_ok_for_constraint
+				(INTVAL (operand), cn)))
+			  win = true;
+			break;
+
 		      case CT_MEMORY:
 			if (force_reload)
 			  break;

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 7/8] Remove 'I'-'P' and 'G'/'H' cases
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
                   ` (5 preceding siblings ...)
  2014-06-05 21:38 ` [PATCH 6/8] Treat 'I'-'P' as separate subtype Richard Sandiford
@ 2014-06-05 21:41 ` Richard Sandiford
  2014-06-10 18:50   ` Jeff Law
  2014-06-05 21:43 ` [PATCH 8/8] Add a common .md file and define standard constraints there Richard Sandiford
  7 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:41 UTC (permalink / raw)
  To: gcc-patches

After the previous patch, we can remove the separate 'I'-'P' and 'G'/'H'
cases without increasing compile time.  I didn't bother adding the kind of
fast-path for 'G'/'H' that I did for 'I'-'P' since it should be much rarer.

This removes the last use of CONST_DOUBLE_OK_FOR_CONSTRAINT_P, so I deleted
the code that defines it and added it to the poison list.  The only remaining
old-style macro is CONST_INT_OK_FOR_CONSTRAINT_P, which is used by the s390
backend.  If this series is OK I'll follow up with a patch to remove that
usage and poison CONST_INT_OK_FOR_CONSTRAINT_P too.

Richard


gcc/
	* system.h (CONST_DOUBLE_OK_FOR_CONSTRAINT_P): Poison.
	* genpreds.c (have_const_dbl_constraints): Delete.
	(add_constraint): Don't set it.
	(write_tm_preds_h): Don't call CONST_DOUBLE_OK_FOR_CONSTRAINT_P.
	* ira-costs.c (record_reg_classes): Handle CONST_INT and CONST_DOUBLE
	constraints using the lookup_constraint logic.
	* ira-lives.c (single_reg_class): Likewise.
	* ira.c (ira_setup_alts): Likewise.
	* lra-constraints.c (process_alt_operands): Likewise.
	* recog.c (asm_operand_ok, constrain_operands): Likewise.
	* reload.c (find_reloads): Likewise.

Index: gcc/system.h
===================================================================
--- gcc/system.h	2014-06-05 22:05:00.271579419 +0100
+++ gcc/system.h	2014-06-05 22:07:23.048734932 +0100
@@ -933,7 +933,7 @@ #define realloc xrealloc
 	CONST_DOUBLE_OK_FOR_LETTER_P EXTRA_CONSTRAINT			   \
 	REG_CLASS_FROM_CONSTRAINT REG_CLASS_FOR_CONSTRAINT		   \
 	EXTRA_CONSTRAINT_STR EXTRA_MEMORY_CONSTRAINT			   \
-	EXTRA_ADDRESS_CONSTRAINT
+	EXTRA_ADDRESS_CONSTRAINT CONST_DOUBLE_OK_FOR_CONSTRAINT_P
 
 /* Hooks that are no longer used.  */
  #pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE	\
Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-05 22:05:01.980593126 +0100
+++ gcc/genpreds.c	2014-06-05 22:32:31.329547134 +0100
@@ -684,7 +684,6 @@ static const char const_dbl_constraints[
 static bool have_address_constraints;
 static bool have_extra_constraints;
 static bool have_const_int_constraints;
-static bool have_const_dbl_constraints;
 static unsigned int num_constraints;
 
 static const constraint_data **enum_order;
@@ -888,7 +887,6 @@ add_constraint (const char *name, const
   constraint_max_namelen = MAX (constraint_max_namelen, strlen (name));
   have_register_constraints |= c->is_register;
   have_const_int_constraints |= c->is_const_int;
-  have_const_dbl_constraints |= c->is_const_dbl;
   have_extra_constraints |= c->is_extra;
   have_memory_constraints |= c->is_memory;
   have_address_constraints |= c->is_address;
@@ -1375,11 +1373,6 @@ #define GCC_TM_PREDS_H\n\
 	      "{\n"
 	      "  return false;\n"
 	      "}\n");
-      if (have_const_dbl_constraints)
-	puts ("#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n"
-	      "    constraint_satisfied_p (v_, lookup_constraint (s_))\n");
-      else
-	puts ("#define CONST_DOUBLE_OK_FOR_CONSTRAINT_P(v_,c_,s_) 0\n");
 
       puts ("enum constraint_type\n"
 	    "{\n"
Index: gcc/ira-costs.c
===================================================================
--- gcc/ira-costs.c	2014-06-05 22:05:01.981593134 +0100
+++ gcc/ira-costs.c	2014-06-05 22:32:31.329547134 +0100
@@ -703,13 +703,6 @@ record_reg_classes (int n_alts, int n_op
 		    win = 1;
 		  break;
 
-		case 'G':
-		case 'H':
-		  if (CONST_DOUBLE_AS_FLOAT_P (op) 
-		      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
-		    win = 1;
-		  break;
-
 		case 's':
 		  if (CONST_SCALAR_INT_P (op)) 
 		    break;
@@ -725,19 +718,6 @@ record_reg_classes (int n_alts, int n_op
 		    win = 1;
 		  break;
 
-		case 'I':
-		case 'J':
-		case 'K':
-		case 'L':
-		case 'M':
-		case 'N':
-		case 'O':
-		case 'P':
-		  if (CONST_INT_P (op)
-		      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
-		    win = 1;
-		  break;
-
 		case 'X':
 		  win = 1;
 		  break;
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	2014-06-05 22:05:00.264579363 +0100
+++ gcc/ira-lives.c	2014-06-05 22:32:31.329547134 +0100
@@ -801,23 +801,6 @@ single_reg_class (const char *constraint
 	    return NO_REGS;
 	  break;
 
-	case 'I':
-	case 'J':
-	case 'K':
-	case 'L':
-	case 'M':
-	case 'N':
-	case 'O':
-	case 'P':
-	  if ((CONST_INT_P (op)
-	       && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, constraints))
-	      || (equiv_const != NULL_RTX
-		  && CONST_INT_P (equiv_const)
-		  && CONST_OK_FOR_CONSTRAINT_P (INTVAL (equiv_const),
-						c, constraints)))
-	    return NO_REGS;
-	  break;
-
 	case 'E':
 	case 'F':
 	  if (CONST_DOUBLE_AS_FLOAT_P (op) 
@@ -831,17 +814,9 @@ single_reg_class (const char *constraint
 	    return NO_REGS;
 	  break;
 
-	case 'G':
-	case 'H':
-	  if ((CONST_DOUBLE_AS_FLOAT_P (op) 
-	       && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, constraints))
-	      || (equiv_const != NULL_RTX
-		  && CONST_DOUBLE_AS_FLOAT_P (equiv_const) 
-		  && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const,
-						       c, constraints)))
-	    return NO_REGS;
-	  break;
-
+	case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+	case 'O': case 'P':
+	case 'G': case 'H':
 	case 'r':
 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
 	case 'h': case 'j': case 'k': case 'l':
Index: gcc/ira.c
===================================================================
--- gcc/ira.c	2014-06-05 22:05:01.983593150 +0100
+++ gcc/ira.c	2014-06-05 22:32:31.329547134 +0100
@@ -1883,13 +1883,6 @@ ira_setup_alts (rtx insn, HARD_REG_SET &
 		      goto op_success;
 		    break;
 		    
-		  case 'G':
-		  case 'H':
-		    if (CONST_DOUBLE_AS_FLOAT_P (op)
-			&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
-		      goto op_success;
-		    break;
-		    
 		  case 's':
 		    if (CONST_SCALAR_INT_P (op))
 		      break;
@@ -1903,19 +1896,6 @@ ira_setup_alts (rtx insn, HARD_REG_SET &
 		      goto op_success;
 		    break;
 		    
-		  case 'I':
-		  case 'J':
-		  case 'K':
-		  case 'L':
-		  case 'M':
-		  case 'N':
-		  case 'O':
-		  case 'P':
-		    if (CONST_INT_P (op)
-			&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
-		      goto op_success;
-		    break;
-		    
 		  case 'V':
 		    if (MEM_P (op) && ! offsettable_memref_p (op))
 		      goto op_success;
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2014-06-05 22:05:01.985593166 +0100
+++ gcc/lra-constraints.c	2014-06-05 22:32:31.329547134 +0100
@@ -1980,13 +1980,6 @@ process_alt_operands (int only_alternati
 		    win = true;
 		  break;
 
-		case 'G':
-		case 'H':
-		  if (CONST_DOUBLE_AS_FLOAT_P (op)
-		      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
-		    win = true;
-		  break;
-
 		case 's':
 		  if (CONST_SCALAR_INT_P (op))
 		    break;
@@ -2001,19 +1994,6 @@ process_alt_operands (int only_alternati
 		    win = true;
 		  break;
 
-		case 'I':
-		case 'J':
-		case 'K':
-		case 'L':
-		case 'M':
-		case 'N':
-		case 'O':
-		case 'P':
-		  if (CONST_INT_P (op)
-		      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
-		    win = true;
-		  break;
-
 		case 'X':
 		  /* This constraint should be excluded by the fast
 		     track.  */
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	2014-06-05 22:05:01.986593174 +0100
+++ gcc/recog.c	2014-06-05 22:32:31.329547134 +0100
@@ -1827,17 +1827,6 @@ asm_operand_ok (rtx op, const char *cons
 	    result = 1;
 	  break;
 
-	case 'G':
-	  if (CONST_DOUBLE_AS_FLOAT_P (op)
-	      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', constraint))
-	    result = 1;
-	  break;
-	case 'H':
-	  if (CONST_DOUBLE_AS_FLOAT_P (op)
-	      && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'H', constraint))
-	    result = 1;
-	  break;
-
 	case 's':
 	  if (CONST_SCALAR_INT_P (op))
 	    break;
@@ -1853,47 +1842,6 @@ asm_operand_ok (rtx op, const char *cons
 	    result = 1;
 	  break;
 
-	case 'I':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
-	    result = 1;
-	  break;
-	case 'J':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
-	    result = 1;
-	  break;
-	case 'K':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
-	    result = 1;
-	  break;
-	case 'L':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
-	    result = 1;
-	  break;
-	case 'M':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
-	    result = 1;
-	  break;
-	case 'N':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
-	    result = 1;
-	  break;
-	case 'O':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
-	    result = 1;
-	  break;
-	case 'P':
-	  if (CONST_INT_P (op)
-	      && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
-	    result = 1;
-	  break;
-
 	case 'X':
 	  result = 1;
 	  break;
@@ -2802,13 +2750,6 @@ constrain_operands (int strict)
 		  win = 1;
 		break;
 
-	      case 'G':
-	      case 'H':
-		if (CONST_DOUBLE_AS_FLOAT_P (op)
-		    && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
-		  win = 1;
-		break;
-
 	      case 's':
 		if (CONST_SCALAR_INT_P (op))
 		  break;
@@ -2822,19 +2763,6 @@ constrain_operands (int strict)
 		  win = 1;
 		break;
 
-	      case 'I':
-	      case 'J':
-	      case 'K':
-	      case 'L':
-	      case 'M':
-	      case 'N':
-	      case 'O':
-	      case 'P':
-		if (CONST_INT_P (op)
-		    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
-		  win = 1;
-		break;
-
 	      case 'V':
 		if (MEM_P (op)
 		    && ((strict > 0 && ! offsettable_memref_p (op))
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2014-06-05 22:07:49.950954766 +0100
+++ gcc/reload.c	2014-06-05 22:40:14.946489460 +0100
@@ -3434,13 +3434,6 @@ find_reloads (rtx insn, int replace, int
 		      win = 1;
 		    break;
 
-		  case 'G':
-		  case 'H':
-		    if (CONST_DOUBLE_AS_FLOAT_P (operand)
-			&& CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
-		      win = 1;
-		    break;
-
 		  case 's':
 		    if (CONST_SCALAR_INT_P (operand))
 		      break;
@@ -3455,19 +3448,6 @@ find_reloads (rtx insn, int replace, int
 		      win = 1;
 		    break;
 
-		  case 'I':
-		  case 'J':
-		  case 'K':
-		  case 'L':
-		  case 'M':
-		  case 'N':
-		  case 'O':
-		  case 'P':
-		    if (CONST_INT_P (operand)
-			&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
-		      win = 1;
-		    break;
-
 		  case 'X':
 		    force_reload = 0;
 		    win = 1;

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
                   ` (6 preceding siblings ...)
  2014-06-05 21:41 ` [PATCH 7/8] Remove 'I'-'P' and 'G'/'H' cases Richard Sandiford
@ 2014-06-05 21:43 ` Richard Sandiford
  2014-06-10 20:59   ` Jeff Law
  2014-06-12 19:24   ` Segher Boessenkool
  7 siblings, 2 replies; 25+ messages in thread
From: Richard Sandiford @ 2014-06-05 21:43 UTC (permalink / raw)
  To: gcc-patches

This final patch uses a common .md file to define all standard
constraints except 'g'.  It then gets rid of explicit case statements
for the standard constraints, except in two cases:

(1) recog.c:asm_operand_ok still needs to handle 'o' specially for
    targets like ia64 that don't have offsettable addresses.  See the
    comment there for justification.

(2) the trickier cases in reload.  I'm not changing those more than I have to.

I did wonder about defining a new rtl construct that could be used for 'g',
so that even that special case goes away.  In the end I think it would be
a false abstraction though.  No other constraint allows (or IMO should allow)
all three of a register class, a base-reloadable memory and a constant,
so handling it in the lookup_constraint paths would make things more
complicated rather than less.

Note that the s390 'e' constraint is TARGET_MEM_CONSTRAINT, which is now
defined in the common file.

I put the common .md file in the main gcc/ directory by analogy with
defaults.h and common.opt.  It could instead go in config/ or config/common/,
if those sound better.

Richard


gcc/
	* common.md: New file.
	* doc/md.texi: Update description of generic, machine-independent
	constraints.
	* config/s390/constraints.md (e): Delete.
	* Makefile.in (md_file): Include common.md.
	* config/m32c/t-m32c (md_file): Likewise.
	* genpreds.c (general_mem): New array.
	(generic_constraint_letters): Remove constraints now defined by
	common.md.
	(add_constraint): Map TARGET_MEM_CONSTRAINT to general_mem.
	Allow the first character to be '<' or '>' as well.
	* genoutput.c (general_mem): New array.
	(indep_constraints): Remove constraints now defined by common.md.
	(note_constraint): Map TARGET_MEM_CONSTRAINT to general_mem.
	Remove special handling of 'm'.
	* ira-costs.c (record_reg_classes): Remove special handling of
	constraints now defined by common.md.
	* ira.c (ira_setup_alts, ira_get_dup_out_num): Likewise.
	* ira-lives.c (single_reg_class): Likewise.
	(ira_implicitly_set_insn_hard_regs): Likewise.
	* lra-constraints.c (reg_class_from_constraints): Likewise.
	(process_alt_operands, process_address, curr_insn_transform): Likewise.
	* postreload.c (reload_cse_simplify_operands): Likewise.
	* reload.c (push_secondary_reload, scratch_reload_class)
	(find_reloads, alternative_allows_const_pool_ref): Likewise.
	* reload1.c (maybe_fix_stack_asms): Likewise.
	* targhooks.c (default_secondary_reload): Likewise.
	* stmt.c (parse_output_constraint): Likewise.
	* recog.c (preprocess_constraints): Likewise.
	(constrain_operands, peep2_find_free_register): Likewise.
	(asm_operand_ok): Likewise, but add a comment saying why 'o'
	must be handled specially.

Index: gcc/common.md
===================================================================
--- /dev/null	2014-05-18 17:42:44.871287828 +0100
+++ gcc/common.md	2014-06-05 22:40:45.977752252 +0100
@@ -0,0 +1,95 @@
+;; Common GCC machine description file, shared by all targets.
+;; Copyright (C) 2014 Free Software Foundation, Inc.
+;;
+;; This file is part of GCC.
+;;
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.  */
+
+(define_register_constraint "r" "GENERAL_REGS"
+  "Matches any general register.")
+
+(define_memory_constraint "TARGET_MEM_CONSTRAINT"
+  "Matches any valid memory."
+  (and (match_code "mem")
+       (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
+						 MEM_ADDR_SPACE (op))")))
+
+(define_memory_constraint "o"
+  "Matches an offsettable memory reference."
+  (and (match_code "mem")
+       (match_test "offsettable_nonstrict_memref_p (op)")))
+
+;; "V" matches TARGET_MEM_CONSTRAINTs that are rejected by "o".
+;; This means that it is not a memory constraint in the usual sense,
+;; since reloading the address into a base register would make the
+;; address offsettable.
+(define_constraint "V"
+  "Matches a non-offsettable memory reference."
+  (and (match_code "mem")
+       (match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
+						 MEM_ADDR_SPACE (op))")
+       (not (match_test "offsettable_nonstrict_memref_p (op)"))))
+
+;; Like "V", this is not a memory constraint, since reloading the address
+;; into a base register would cause it not to match.
+(define_constraint "<"
+  "Matches a pre-dec or post-dec operand."
+  (and (match_code "mem")
+       (ior (match_test "GET_CODE (XEXP (op, 0)) == PRE_DEC")
+       	    (match_test "GET_CODE (XEXP (op, 0)) == POST_DEC"))))
+
+;; See the comment for "<".
+(define_constraint ">"
+  "Matches a pre-inc or post-inc operand."
+  (and (match_code "mem")
+       (ior (match_test "GET_CODE (XEXP (op, 0)) == PRE_INC")
+       	    (match_test "GET_CODE (XEXP (op, 0)) == POST_INC"))))
+
+(define_address_constraint "p"
+  "Matches a general address."
+  (match_test "address_operand (op, VOIDmode)"))
+
+(define_constraint "i"
+  "Matches a general integer constant."
+  (and (match_test "CONSTANT_P (op)")
+       (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)")))
+
+(define_constraint "s"
+  "Matches a symbolic integer constant."
+  (and (match_test "CONSTANT_P (op)")
+       (match_test "!CONST_SCALAR_INT_P (op)")
+       (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)")))
+
+(define_constraint "n"
+  "Matches a non-symbolic integer constant."
+  (and (match_test "CONST_SCALAR_INT_P (op)")
+       (match_test "!flag_pic || LEGITIMATE_PIC_OPERAND_P (op)")))
+
+(define_constraint "E"
+  "Matches a floating-point constant."
+  (ior (match_test "CONST_DOUBLE_AS_FLOAT_P (op)")
+       (match_test "GET_CODE (op) == CONST_VECTOR
+		    && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT")))
+
+;; There is no longer a distinction between "E" and "F".
+(define_constraint "F"
+  "Matches a floating-point constant."
+  (ior (match_test "CONST_DOUBLE_AS_FLOAT_P (op)")
+       (match_test "GET_CODE (op) == CONST_VECTOR
+		    && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT")))
+
+(define_constraint "X"
+  "Matches anything."
+  (match_test "true"))
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	2014-06-05 22:32:31.329547134 +0100
+++ gcc/doc/md.texi	2014-06-05 22:40:45.995752404 +0100
@@ -4355,16 +4355,8 @@ Use this for constraints that should not
 It is occasionally useful to test a constraint from C code rather than
 implicitly via the constraint string in a @code{match_operand}.  The
 generated file @file{tm_p.h} declares a few interfaces for working
-with machine-specific constraints.  None of these interfaces work with
-the generic constraints described in @ref{Simple Constraints}.  This
-may change in the future.
-
-@strong{Warning:} @file{tm_p.h} may declare other functions that
-operate on constraints, besides the ones documented here.  Do not use
-those functions from machine-dependent code.  They exist to implement
-the old constraint interface that machine-independent components of
-the compiler still expect.  They will change or disappear in the
-future.
+with constraints.  At present these are defined for all constraints
+except @code{g} (which is equivalent to @code{general_operand}).
 
 Some valid constraint names are not valid C identifiers, so there is a
 mangling scheme for referring to them from C@.  Constraint names that
@@ -4391,17 +4383,14 @@ the variable @var{m} is a mangled constr
 a larger identifier).
 
 @deftp Enum constraint_num
-For each machine-specific constraint, there is a corresponding
+For each constraint except @code{g}, there is a corresponding
 enumeration constant: @samp{CONSTRAINT_} plus the mangled name of the
 constraint.  Functions that take an @code{enum constraint_num} as an
 argument expect one of these constants.
-
-Machine-independent constraints do not have associated constants.
-This may change in the future.
 @end deftp
 
 @deftypefun {inline bool} satisfies_constraint_@var{m} (rtx @var{exp})
-For each machine-specific, non-register constraint @var{m}, there is
+For each non-register constraint @var{m} except @code{g}, there is
 one of these functions; it returns @code{true} if @var{exp} satisfies the
 constraint.  These functions are only visible if @file{rtl.h} was included
 before @file{tm_p.h}.
Index: gcc/config/s390/constraints.md
===================================================================
--- gcc/config/s390/constraints.md	2014-06-05 22:32:31.329547134 +0100
+++ gcc/config/s390/constraints.md	2014-06-05 22:40:45.988752345 +0100
@@ -406,14 +406,6 @@ (define_memory_constraint "b"
                && s390_check_symref_alignment (XEXP (op, 0),
                                                GET_MODE_SIZE (GET_MODE (op)))"))
 
-(define_memory_constraint "e"
-  "Matches all memory references available on the current architecture
-level.  This constraint will never be used and using it in an inline
-assembly is *always* a bug since there is no instruction accepting all
-those addresses.  It just serves as a placeholder for a generic memory
-constraint."
-  (match_test "strict_memory_address_p (GET_MODE (op), op)"))
-
 ; This defines 'm' as normal memory constraint.  This is only possible
 ; since the standard memory constraint is re-defined in s390.h using
 ; the TARGET_MEM_CONSTRAINT macro.
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	2014-06-05 22:32:31.329547134 +0100
+++ gcc/Makefile.in	2014-06-05 22:40:45.976752243 +0100
@@ -491,7 +491,7 @@ out_file=$(srcdir)/config/@out_file@
 out_object_file=@out_object_file@
 common_out_file=$(srcdir)/common/config/@common_out_file@
 common_out_object_file=@common_out_object_file@
-md_file=$(srcdir)/config/@md_file@
+md_file=$(srcdir)/common.md $(srcdir)/config/@md_file@
 tm_file_list=@tm_file_list@
 tm_include_list=@tm_include_list@
 tm_defines=@tm_defines@
Index: gcc/config/m32c/t-m32c
===================================================================
--- gcc/config/m32c/t-m32c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/config/m32c/t-m32c	2014-06-05 22:40:45.993752387 +0100
@@ -20,7 +20,7 @@
 
 # target-specific files
 
-md_file = md
+md_file = $(srcdir)/common.md md
 
 MD_FILES = m32c constraints predicates addsub bitops blkmov cond jump minmax mov muldiv prologue shift
 
Index: gcc/genpreds.c
===================================================================
--- gcc/genpreds.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/genpreds.c	2014-06-05 22:40:45.977752252 +0100
@@ -30,6 +30,8 @@ the Free Software Foundation; either ver
 #include "read-md.h"
 #include "gensupport.h"
 
+static char general_mem[] = { TARGET_MEM_CONSTRAINT, 0 };
+
 /* Given a predicate expression EXP, from form NAME at line LINENO,
    verify that it does not contain any RTL constructs which are not
    valid in predicate definitions.  Returns true if EXP is
@@ -664,7 +666,7 @@ #define FOR_ALL_CONSTRAINTS(iter_) \
    The 'm' constraint is not mentioned here since that constraint
    letter can be overridden by the back end by defining the
    TARGET_MEM_CONSTRAINT macro.  */
-static const char generic_constraint_letters[] = "EFVXginoprs";
+static const char generic_constraint_letters[] = "g";
 
 /* Machine-independent code expects that constraints with these
    (initial) letters will allow only (a subset of all) CONST_INTs.  */
@@ -735,19 +737,12 @@ add_constraint (const char *name, const
   bool is_const_dbl;
   size_t namelen;
 
+  if (strcmp (name, "TARGET_MEM_CONSTRAINT") == 0)
+    name = general_mem;
+
   if (exp && validate_exp (exp, name, lineno))
     return;
 
-  if (!ISALPHA (name[0]) && name[0] != '_')
-    {
-      if (name[1] == '\0')
-	error_with_line (lineno, "constraint name '%s' is not "
-			 "a letter or underscore", name);
-      else
-	error_with_line (lineno, "constraint name '%s' does not begin "
-			 "with a letter or underscore", name);
-      return;
-    }
   for (p = name; *p; p++)
     if (!ISALNUM (*p))
       {
Index: gcc/genoutput.c
===================================================================
--- gcc/genoutput.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/genoutput.c	2014-06-05 22:40:45.978752260 +0100
@@ -98,6 +98,8 @@ Software Foundation; either version 3, o
 
 #define MAX_MAX_OPERANDS 40
 
+static char general_mem[] = { TARGET_MEM_CONSTRAINT, 0 };
+
 static int n_occurrences		(int, const char *);
 static const char *strip_whitespace	(const char *);
 
@@ -208,7 +210,7 @@ struct constraint_data
 /* This is a complete list (unlike the one in genpreds.c) of constraint
    letters and modifiers with machine-independent meaning.  The only
    omission is digits, as these are handled specially.  */
-static const char indep_constraints[] = ",=+%*?!#&<>EFVXgimnoprs";
+static const char indep_constraints[] = ",=+%*?!#&g";
 
 static struct constraint_data *
 constraints_by_letter_table[1 << CHAR_BIT];
@@ -1151,13 +1153,13 @@ strip_whitespace (const char *s)
 note_constraint (rtx exp, int lineno)
 {
   const char *name = XSTR (exp, 0);
-  unsigned int namelen = strlen (name);
   struct constraint_data **iter, **slot, *new_cdata;
 
-  /* The 'm' constraint is special here since that constraint letter
-     can be overridden by the back end by defining the
-     TARGET_MEM_CONSTRAINT macro.  */
-  if (strchr (indep_constraints, name[0]) && name[0] != 'm')
+  if (strcmp (name, "TARGET_MEM_CONSTRAINT") == 0)
+    name = general_mem;
+  unsigned int namelen = strlen (name);
+
+  if (strchr (indep_constraints, name[0]))
     {
       if (name[1] == '\0')
 	error_with_line (lineno, "constraint letter '%s' cannot be "
Index: gcc/ira-costs.c
===================================================================
--- gcc/ira-costs.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/ira-costs.c	2014-06-05 22:40:45.979752269 +0100
@@ -645,8 +645,6 @@ record_reg_classes (int n_alts, int n_op
 	    {
 	      switch (c)
 		{
-		case ',':
-		  break;
 		case '*':
 		  /* Ignore the next letter for this pass.  */
 		  c = *++p;
@@ -654,72 +652,6 @@ record_reg_classes (int n_alts, int n_op
 
 		case '?':
 		  alt_cost += 2;
-		case '!':  case '#':  case '&':
-		case '0':  case '1':  case '2':  case '3':  case '4':
-		case '5':  case '6':  case '7':  case '8':  case '9':
-		  break;
-
-		case 'p':
-		  allows_addr = 1;
-		  win = address_operand (op, GET_MODE (op));
-		  /* We know this operand is an address, so we want it
-		     to be allocated to a register that can be the
-		     base of an address, i.e. BASE_REG_CLASS.  */
-		  classes[i]
-		    = ira_reg_class_subunion[classes[i]]
-		      [base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-				       ADDRESS, SCRATCH)];
-		  break;
-
-		case 'm':  case 'o':  case 'V':
-		  /* It doesn't seem worth distinguishing between
-		     offsettable and non-offsettable addresses
-		     here.  */
-		  insn_allows_mem[i] = allows_mem[i] = 1;
-		  if (MEM_P (op))
-		    win = 1;
-		  break;
-
-		case '<':
-		  if (MEM_P (op)
-		      && (GET_CODE (XEXP (op, 0)) == PRE_DEC
-			  || GET_CODE (XEXP (op, 0)) == POST_DEC))
-		    win = 1;
-		  break;
-
-		case '>':
-		  if (MEM_P (op)
-		      && (GET_CODE (XEXP (op, 0)) == PRE_INC
-			  || GET_CODE (XEXP (op, 0)) == POST_INC))
-		    win = 1;
-		  break;
-
-		case 'E':
-		case 'F':
-		  if (CONST_DOUBLE_AS_FLOAT_P (op) 
-		      || (GET_CODE (op) == CONST_VECTOR
-			  && (GET_MODE_CLASS (GET_MODE (op))
-			      == MODE_VECTOR_FLOAT)))
-		    win = 1;
-		  break;
-
-		case 's':
-		  if (CONST_SCALAR_INT_P (op)) 
-		    break;
-
-		case 'i':
-		  if (CONSTANT_P (op)
-		      && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
-		    win = 1;
-		  break;
-
-		case 'n':
-		  if (CONST_SCALAR_INT_P (op)) 
-		    win = 1;
-		  break;
-
-		case 'X':
-		  win = 1;
 		  break;
 
 		case 'g':
@@ -728,7 +660,6 @@ record_reg_classes (int n_alts, int n_op
 			  && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))))
 		    win = 1;
 		  insn_allows_mem[i] = allows_mem[i] = 1;
-		case 'r':
 		  classes[i] = ira_reg_class_subunion[classes[i]][GENERAL_REGS];
 		  break;
 
Index: gcc/ira.c
===================================================================
--- gcc/ira.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/ira.c	2014-06-05 22:40:45.981752286 +0100
@@ -1835,9 +1835,6 @@ ira_setup_alts (rtx insn, HARD_REG_SET &
 		    len = 0;
 		    break;
 		  
-		  case '?':  case '!': case '*':  case '=':  case '+':
-		    break;
-		    
 		  case '%':
 		    /* We only support one commutative marker, the
 		       first one.  We already set commutative
@@ -1846,63 +1843,12 @@ ira_setup_alts (rtx insn, HARD_REG_SET &
 		      commutative = nop;
 		    break;
 
-		  case '&':
-		    break;
-		    
 		  case '0':  case '1':  case '2':  case '3':  case '4':
 		  case '5':  case '6':  case '7':  case '8':  case '9':
 		    goto op_success;
 		    break;
 		    
-		  case 'p':
 		  case 'g':
-		  case 'X':
-		  case TARGET_MEM_CONSTRAINT:
-		    goto op_success;
-		    break;
-		    
-		  case '<':
-		    if (MEM_P (op)
-			&& (GET_CODE (XEXP (op, 0)) == PRE_DEC
-			    || GET_CODE (XEXP (op, 0)) == POST_DEC))
-		    goto op_success;
-		    break;
-		    
-		  case '>':
-		    if (MEM_P (op)
-		      && (GET_CODE (XEXP (op, 0)) == PRE_INC
-			  || GET_CODE (XEXP (op, 0)) == POST_INC))
-		      goto op_success;
-		    break;
-		    
-		  case 'E':
-		  case 'F':
-		    if (CONST_DOUBLE_AS_FLOAT_P (op)
-			|| (GET_CODE (op) == CONST_VECTOR
-			    && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-		      goto op_success;
-		    break;
-		    
-		  case 's':
-		    if (CONST_SCALAR_INT_P (op))
-		      break;
-		  case 'i':
-		    if (CONSTANT_P (op))
-		      goto op_success;
-		    break;
-		    
-		  case 'n':
-		    if (CONST_SCALAR_INT_P (op))
-		      goto op_success;
-		    break;
-		    
-		  case 'V':
-		    if (MEM_P (op) && ! offsettable_memref_p (op))
-		      goto op_success;
-		    break;
-		    
-		  case 'o':
-		  case 'r':
 		    goto op_success;
 		    break;
 		    
@@ -1992,21 +1938,9 @@ ira_get_dup_out_num (int op_num, HARD_RE
 	  else if (! ignore_p)
 	    switch (c)
 	      {
-	      case 'X':
-	      case 'p':
 	      case 'g':
 		goto fail;
-	      case 'r':
-		if (!targetm.class_likely_spilled_p (GENERAL_REGS))
-		  goto fail;
-		break;
-	      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-	      case 'h': case 'j': case 'k': case 'l':
-	      case 'q': case 't': case 'u':
-	      case 'v': case 'w': case 'x': case 'y': case 'z':
-	      case 'A': case 'B': case 'C': case 'D':
-	      case 'Q': case 'R': case 'S': case 'T': case 'U':
-	      case 'W': case 'Y': case 'Z':
+	      default:
 		{
 		  enum constraint_num cn = lookup_constraint (str);
 		  enum reg_class cl = reg_class_for_constraint (cn);
Index: gcc/ira-lives.c
===================================================================
--- gcc/ira-lives.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/ira-lives.c	2014-06-05 22:40:45.981752286 +0100
@@ -771,60 +771,10 @@ single_reg_class (const char *constraint
     else if (enabled & 1)
       switch (c)
 	{
-	case ' ':
-	case '\t':
-	case '=':
-	case '+':
-	case '*':
-	case '&':
-	case '%':
-	case '!':
-	case '?':
-	  break;
-	case 'i':
-	  if (CONSTANT_P (op)
-	      || (equiv_const != NULL_RTX && CONSTANT_P (equiv_const)))
-	    return NO_REGS;
-	  break;
-
-	case 'n':
-	  if (CONST_SCALAR_INT_P (op)
-	      || (equiv_const != NULL_RTX && CONST_SCALAR_INT_P (equiv_const)))
-	    return NO_REGS;
-	  break;
-
-	case 's':
-	  if ((CONSTANT_P (op) && !CONST_SCALAR_INT_P (op))
-	      || (equiv_const != NULL_RTX
-		  && CONSTANT_P (equiv_const)
-		  && !CONST_SCALAR_INT_P (equiv_const)))
-	    return NO_REGS;
-	  break;
-
-	case 'E':
-	case 'F':
-	  if (CONST_DOUBLE_AS_FLOAT_P (op) 
-	      || (GET_CODE (op) == CONST_VECTOR
-		  && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT)
-	      || (equiv_const != NULL_RTX
-		  && (CONST_DOUBLE_AS_FLOAT_P (equiv_const)
-		      || (GET_CODE (equiv_const) == CONST_VECTOR
-			  && (GET_MODE_CLASS (GET_MODE (equiv_const))
-			      == MODE_VECTOR_FLOAT)))))
-	    return NO_REGS;
-	  break;
+	case 'g':
+	  return NO_REGS;
 
-	case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
-	case 'O': case 'P':
-	case 'G': case 'H':
-	case 'r':
-	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-	case 'h': case 'j': case 'k': case 'l':
-	case 'q': case 't': case 'u':
-	case 'v': case 'w': case 'x': case 'y': case 'z':
-	case 'A': case 'B': case 'C': case 'D':
-	case 'Q': case 'R': case 'S': case 'T': case 'U':
-	case 'W': case 'Y': case 'Z':
+	default:
 	  /* ??? Is this the best way to handle memory constraints?  */
 	  cn = lookup_constraint (constraints);
 	  if (insn_extra_memory_constraint (cn)
@@ -835,9 +785,7 @@ single_reg_class (const char *constraint
 		  && CONSTANT_P (equiv_const)
 		  && constraint_satisfied_p (equiv_const, cn)))
 	    return NO_REGS;
-	  next_cl = (c == 'r'
-		     ? GENERAL_REGS
-		     : reg_class_for_constraint (cn));
+	  next_cl = reg_class_for_constraint (cn);
 	  if (next_cl == NO_REGS)
 	    break;
 	  if (cl == NO_REGS
@@ -860,9 +808,6 @@ single_reg_class (const char *constraint
 	    return NO_REGS;
 	  cl = next_cl;
 	  break;
-
-	default:
-	  return NO_REGS;
 	}
   return cl;
 }
@@ -913,29 +858,17 @@ ira_implicitly_set_insn_hard_regs (HARD_
 	    else if (c == ',')
 	      enabled >>= 1;
 	    else if (enabled & 1)
-	      switch (c)
-		{
-		case 'r':
-		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-		case 'h': case 'j': case 'k': case 'l':
-		case 'q': case 't': case 'u':
-		case 'v': case 'w': case 'x': case 'y': case 'z':
-		case 'A': case 'B': case 'C': case 'D':
-		case 'Q': case 'R': case 'S': case 'T': case 'U':
-		case 'W': case 'Y': case 'Z':
-		  cl = (c == 'r'
-			? GENERAL_REGS
-			: reg_class_for_constraint (lookup_constraint (p)));
-		  if (cl != NO_REGS)
-		    {
-		      /* There is no register pressure problem if all of the
-			 regs in this class are fixed.  */
-		      int regno = ira_class_singleton[cl][mode];
-		      if (regno >= 0)
-			add_to_hard_reg_set (set, mode, regno);
-		    }
-		  break;
-		}
+	      {
+		cl = reg_class_for_constraint (lookup_constraint (p));
+		if (cl != NO_REGS)
+		  {
+		    /* There is no register pressure problem if all of the
+		       regs in this class are fixed.  */
+		    int regno = ira_class_singleton[cl][mode];
+		    if (regno >= 0)
+		      add_to_hard_reg_set (set, mode, regno);
+		  }
+	      }
 	}
     }
 }
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/lra-constraints.c	2014-06-05 22:40:45.983752303 +0100
@@ -968,14 +968,7 @@ reg_class_from_constraints (const char *
       case ',':
 	return op_class;
 
-      case 'p':
-	op_class = (reg_class_subunion
-		    [op_class][base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-					       ADDRESS, SCRATCH)]);
-	break;
-
       case 'g':
-      case 'r':
 	op_class = reg_class_subunion[op_class][GENERAL_REGS];
 	break;
 
@@ -1768,15 +1761,6 @@ process_alt_operands (int only_alternati
 		  c = '\0';
 		  break;
 
-		case '=':  case '+': case '?': case '*': case '!':
-		case ' ': case '\t':
-		  break;
-
-		case '%':
-		  /* We only support one commutative marker, the first
-		     one.  We already set commutative above.  */
-		  break;
-
 		case '&':
 		  early_clobber_p = true;
 		  break;
@@ -1909,105 +1893,11 @@ process_alt_operands (int only_alternati
 		    break;
 		  }
 
-		case 'p':
-		  cl = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-				       ADDRESS, SCRATCH);
-		  this_alternative = reg_class_subunion[this_alternative][cl];
-		  IOR_HARD_REG_SET (this_alternative_set,
-				    reg_class_contents[cl]);
-		  if (costly_p)
-		    {
-		      this_costly_alternative
-			= reg_class_subunion[this_costly_alternative][cl];
-		      IOR_HARD_REG_SET (this_costly_alternative_set,
-					reg_class_contents[cl]);
-		    }
-		  win = true;
-		  badop = false;
-		  break;
-
-		case TARGET_MEM_CONSTRAINT:
-		  if (MEM_P (op) || spilled_pseudo_p (op))
-		    win = true;
-		  /* We can put constant or pseudo value into memory
-		     to satisfy the constraint.  */
-		  if (CONST_POOL_OK_P (mode, op) || REG_P (op))
-		    badop = false;
-		  constmemok = true;
-		  break;
-
-		case '<':
-		  if (MEM_P (op)
-		      && (GET_CODE (XEXP (op, 0)) == PRE_DEC
-			  || GET_CODE (XEXP (op, 0)) == POST_DEC))
-		    win = true;
-		  break;
-
-		case '>':
-		  if (MEM_P (op)
-		      && (GET_CODE (XEXP (op, 0)) == PRE_INC
-			  || GET_CODE (XEXP (op, 0)) == POST_INC))
-		    win = true;
-		  break;
-
-		  /* Memory op whose address is not offsettable.  */
-		case 'V':
-		  if (MEM_P (op)
-		      && ! offsettable_nonstrict_memref_p (op))
-		    win = true;
-		  break;
-
-		  /* Memory operand whose address is offsettable.  */
-		case 'o':
-		  if ((MEM_P (op)
-		       && offsettable_nonstrict_memref_p (op))
-		      || spilled_pseudo_p (op))
-		    win = true;
-		  /* We can put constant or pseudo value into memory
-		     or make memory address offsetable to satisfy the
-		     constraint.  */
-		  if (CONST_POOL_OK_P (mode, op) || MEM_P (op) || REG_P (op))
-		    badop = false;
-		  constmemok = true;
-		  offmemok = true;
-		  break;
-
-		case 'E':
-		case 'F':
-		  if (GET_CODE (op) == CONST_DOUBLE
-		      || (GET_CODE (op) == CONST_VECTOR
-			  && (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)))
-		    win = true;
-		  break;
-
-		case 's':
-		  if (CONST_SCALAR_INT_P (op))
-		    break;
-
-		case 'i':
-		  if (general_constant_p (op))
-		    win = true;
-		  break;
-
-		case 'n':
-		  if (CONST_SCALAR_INT_P (op))
-		    win = true;
-		  break;
-
-		case 'X':
-		  /* This constraint should be excluded by the fast
-		     track.  */
-		  gcc_unreachable ();
-		  break;
-
 		case 'g':
 		  if (MEM_P (op)
 		      || general_constant_p (op)
 		      || spilled_pseudo_p (op))
 		    win = true;
-		  /* Drop through into 'r' case.  */
-
-		case 'r':
 		  cl = GENERAL_REGS;
 		  goto reg;
 
@@ -2821,8 +2711,7 @@ process_address_1 (int nop, rtx *before,
   enum constraint_num cn = lookup_constraint (constraint);
   bool change_p;
 
-  if (constraint[0] == 'p'
-      || insn_extra_address_constraint (cn))
+  if (insn_extra_address_constraint (cn))
     decompose_lea_address (&ad, curr_id->operand_loc[nop]);
   else if (MEM_P (op))
     decompose_mem_address (&ad, op);
@@ -2853,8 +2742,7 @@ process_address_1 (int nop, rtx *before,
 
   /* Target hooks sometimes don't treat extra-constraint addresses as
      legitimate address_operands, so handle them specially.  */
-  if (constraint[0] != 'p'
-      && insn_extra_address_constraint (cn)
+  if (insn_extra_address_constraint (cn)
       && satisfies_address_constraint_p (&ad, cn))
     return change_p;
 
@@ -3569,8 +3457,6 @@ curr_insn_transform (void)
 		 (c = *constraint) && c != ',' && c != '#';
 		 constraint += CONSTRAINT_LEN (c, constraint))
 	      {
-		if (c == TARGET_MEM_CONSTRAINT || c == 'o')
-		  break;
 		enum constraint_num cn = lookup_constraint (constraint);
 		if (insn_extra_memory_constraint (cn)
 		    && satisfies_memory_constraint_p (tem, cn))
Index: gcc/postreload.c
===================================================================
--- gcc/postreload.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/postreload.c	2014-06-05 22:40:45.987752337 +0100
@@ -553,22 +553,8 @@ reload_cse_simplify_operands (rtx insn,
 
 	      switch (c)
 		{
-		case '=':  case '+':  case '?':
-		case '#':  case '&':  case '!':
-		case '*':  case '%':
-		case '0':  case '1':  case '2':  case '3':  case '4':
-		case '5':  case '6':  case '7':  case '8':  case '9':
-		case '<':  case '>':  case 'V':  case 'o':
-		case 'E':  case 'F':  case 'G':  case 'H':
-		case 's':  case 'i':  case 'n':
-		case 'I':  case 'J':  case 'K':  case 'L':
-		case 'M':  case 'N':  case 'O':  case 'P':
-		case 'p':  case 'X':  case TARGET_MEM_CONSTRAINT:
-		  /* These don't say anything we care about.  */
-		  break;
-
-		case 'g': case 'r':
-		  rclass = reg_class_subunion[(int) rclass][(int) GENERAL_REGS];
+		case 'g':
+		  rclass = reg_class_subunion[rclass][GENERAL_REGS];
 		  break;
 
 		default:
Index: gcc/reload.c
===================================================================
--- gcc/reload.c	2014-06-05 22:40:14.946489460 +0100
+++ gcc/reload.c	2014-06-05 22:40:45.992752379 +0100
@@ -328,7 +328,6 @@ push_secondary_reload (int in_p, rtx x,
   enum reload_type secondary_type;
   int s_reload, t_reload = -1;
   const char *scratch_constraint;
-  char letter;
   secondary_reload_info sri;
 
   if (type == RELOAD_FOR_INPUT_ADDRESS
@@ -399,10 +398,8 @@ push_secondary_reload (int in_p, rtx x,
       scratch_constraint++;
       if (*scratch_constraint == '&')
 	scratch_constraint++;
-      letter = *scratch_constraint;
-      scratch_class = (letter == 'r' ? GENERAL_REGS
-		       : (reg_class_for_constraint
-			  (lookup_constraint (scratch_constraint))));
+      scratch_class = (reg_class_for_constraint
+		       (lookup_constraint (scratch_constraint)));
 
       rclass = scratch_class;
       mode = insn_data[(int) icode].operand[2].mode;
@@ -548,7 +545,6 @@ enum reg_class
 scratch_reload_class (enum insn_code icode)
 {
   const char *scratch_constraint;
-  char scratch_letter;
   enum reg_class rclass;
 
   gcc_assert (insn_data[(int) icode].n_operands == 3);
@@ -557,9 +553,6 @@ scratch_reload_class (enum insn_code ico
   scratch_constraint++;
   if (*scratch_constraint == '&')
     scratch_constraint++;
-  scratch_letter = *scratch_constraint;
-  if (scratch_letter == 'r')
-    return GENERAL_REGS;
   rclass = reg_class_for_constraint (lookup_constraint (scratch_constraint));
   gcc_assert (rclass != NO_REGS);
   return rclass;
@@ -2850,9 +2843,8 @@ find_reloads (rtx insn, int replace, int
       if (*constraints[i] == 0)
 	/* Ignore things like match_operator operands.  */
 	;
-      else if (constraints[i][0] == 'p'
-	       || (insn_extra_address_constraint
-		   (lookup_constraint (constraints[i]))))
+      else if (insn_extra_address_constraint
+	       (lookup_constraint (constraints[i])))
 	{
 	  address_operand_reloaded[i]
 	    = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
@@ -3209,14 +3201,6 @@ find_reloads (rtx insn, int replace, int
 		    c = '\0';
 		    break;
 
-		  case '=':  case '+':  case '*':
-		    break;
-
-		  case '%':
-		    /* We only support one commutative marker, the first
-		       one.  We already set commutative above.  */
-		    break;
-
 		  case '?':
 		    reject += 6;
 		    break;
@@ -3425,29 +3409,6 @@ find_reloads (rtx insn, int replace, int
 		    earlyclobber = 1, this_earlyclobber = 1;
 		    break;
 
-		  case 'E':
-		  case 'F':
-		    if (CONST_DOUBLE_AS_FLOAT_P (operand)
-			|| (GET_CODE (operand) == CONST_VECTOR
-			    && (GET_MODE_CLASS (GET_MODE (operand))
-				== MODE_VECTOR_FLOAT)))
-		      win = 1;
-		    break;
-
-		  case 's':
-		    if (CONST_SCALAR_INT_P (operand))
-		      break;
-		  case 'i':
-		    if (CONSTANT_P (operand)
-			&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)))
-		      win = 1;
-		    break;
-
-		  case 'n':
-		    if (CONST_SCALAR_INT_P (operand))
-		      win = 1;
-		    break;
-
 		  case 'X':
 		    force_reload = 0;
 		    win = 1;
@@ -3468,9 +3429,6 @@ find_reloads (rtx insn, int replace, int
 			    || (REGNO (operand) >= FIRST_PSEUDO_REGISTER
 				&& reg_renumber[REGNO (operand)] < 0)))
 		      win = 1;
-		    /* Drop through into 'r' case.  */
-
-		  case 'r':
 		    cl = GENERAL_REGS;
 		    goto reg;
 
@@ -4677,8 +4635,6 @@ alternative_allows_const_pool_ref (rtx m
   for (; (c = *constraint) && c != ',' && c != '#';
        constraint += CONSTRAINT_LEN (c, constraint))
     {
-      if (c == TARGET_MEM_CONSTRAINT || c == 'o')
-	return true;
       enum constraint_num cn = lookup_constraint (constraint);
       if (insn_extra_memory_constraint (cn)
 	  && (mem == NULL || constraint_satisfied_p (mem, cn)))
Index: gcc/reload1.c
===================================================================
--- gcc/reload1.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/reload1.c	2014-06-05 22:40:45.990752362 +0100
@@ -1417,22 +1417,7 @@ maybe_fix_stack_asms (void)
 
 	      switch (c)
 		{
-		case '=': case '+': case '*': case '%': case '?': case '!':
-		case '0': case '1': case '2': case '3': case '4': case '<':
-		case '>': case 'V': case 'o': case '&': case 'E': case 'F':
-		case 's': case 'i': case 'n': case 'X': case 'I': case 'J':
-		case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
-		case TARGET_MEM_CONSTRAINT:
-		  break;
-
-		case 'p':
-		  cls = (int) reg_class_subunion[cls]
-		      [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-					     ADDRESS, SCRATCH)];
-		  break;
-
 		case 'g':
-		case 'r':
 		  cls = (int) reg_class_subunion[cls][(int) GENERAL_REGS];
 		  break;
 
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/targhooks.c	2014-06-05 22:40:45.987752337 +0100
@@ -919,7 +919,6 @@ default_secondary_reload (bool in_p ATTR
       else if (icode != CODE_FOR_nothing)
 	{
 	  const char *insn_constraint, *scratch_constraint;
-	  char insn_letter, scratch_letter;
 	  enum reg_class insn_class, scratch_class;
 
 	  gcc_assert (insn_data[(int) icode].n_operands == 3);
@@ -933,11 +932,8 @@ default_secondary_reload (bool in_p ATTR
 		  gcc_assert (*insn_constraint == '=');
 		  insn_constraint++;
 		}
-	      insn_letter = *insn_constraint;
-	      insn_class
-		= (insn_letter == 'r' ? GENERAL_REGS
-		   : (reg_class_for_constraint
-		      (lookup_constraint (insn_constraint))));
+	      insn_class = (reg_class_for_constraint
+			    (lookup_constraint (insn_constraint)));
 	      gcc_assert (insn_class != NO_REGS);
 	    }
 
@@ -951,11 +947,8 @@ default_secondary_reload (bool in_p ATTR
 	  scratch_constraint++;
 	  if (*scratch_constraint == '&')
 	    scratch_constraint++;
-	  scratch_letter = *scratch_constraint;
-	  scratch_class
-	    = (scratch_letter == 'r' ? GENERAL_REGS
-	       : (reg_class_for_constraint
-		  (lookup_constraint (scratch_constraint))));
+	  scratch_class = (reg_class_for_constraint
+			   (lookup_constraint (scratch_constraint)));
 
 	  if (reg_class_subset_p (reload_class, insn_class))
 	    {
Index: gcc/stmt.c
===================================================================
--- gcc/stmt.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/stmt.c	2014-06-05 22:40:45.986752328 +0100
@@ -286,10 +286,6 @@ parse_output_constraint (const char **co
 	  }
 	break;
 
-      case 'V':  case TARGET_MEM_CONSTRAINT:  case 'o':
-	*allows_mem = true;
-	break;
-
       case '?':  case '!':  case '*':  case '&':  case '#':
       case 'E':  case 'F':  case 'G':  case 'H':
       case 's':  case 'i':  case 'n':
@@ -315,10 +311,6 @@ parse_output_constraint (const char **co
 	*allows_mem = true;
 	break;
 
-      case 'p': case 'r':
-	*allows_reg = true;
-	break;
-
       default:
 	if (!ISALPHA (*p))
 	  break;
@@ -383,10 +375,6 @@ parse_input_constraint (const char **con
 	  }
 	break;
 
-      case 'V':  case TARGET_MEM_CONSTRAINT:  case 'o':
-	*allows_mem = true;
-	break;
-
       case '<':  case '>':
       case '?':  case '!':  case '*':  case '#':
       case 'E':  case 'F':  case 'G':  case 'H':
@@ -437,10 +425,6 @@ parse_input_constraint (const char **con
 	}
 	/* Fall through.  */
 
-      case 'p':  case 'r':
-	*allows_reg = true;
-	break;
-
       case 'g':  case 'X':
 	*allows_reg = true;
 	*allows_mem = true;
Index: gcc/recog.c
===================================================================
--- gcc/recog.c	2014-06-05 22:32:31.329547134 +0100
+++ gcc/recog.c	2014-06-05 22:40:45.985752320 +0100
@@ -1737,15 +1737,6 @@ asm_operand_ok (rtx op, const char *cons
 	case ',':
 	  constraint++;
 	  continue;
-	case '=':
-	case '+':
-	case '*':
-	case '%':
-	case '!':
-	case '#':
-	case '&':
-	case '?':
-	  break;
 
 	case '0': case '1': case '2': case '3': case '4':
 	case '5': case '6': case '7': case '8': case '9':
@@ -1774,98 +1765,47 @@ asm_operand_ok (rtx op, const char *cons
 	    }
 	  continue;
 
-	case 'p':
-	  if (address_operand (op, VOIDmode))
-	    result = 1;
-	  break;
-
-	case TARGET_MEM_CONSTRAINT:
-	case 'V': /* non-offsettable */
-	  if (memory_operand (op, VOIDmode))
-	    result = 1;
-	  break;
-
+	  /* The rest of the compiler assumes that reloading the address
+	     of a MEM into a register will make it fit an 'o' constraint.
+	     That is, if it sees a MEM operand for an 'o' constraint,
+	     it assumes that (mem (base-reg)) will fit.
+
+	     That assumption fails on targets that don't have offsettable
+	     addresses at all.  We therefore need to treat 'o' asm
+	     constraints as a special case and only accept operands that
+	     are already offsettable, thus proving that at least one
+	     offsettable address exists.  */
 	case 'o': /* offsettable */
 	  if (offsettable_nonstrict_memref_p (op))
 	    result = 1;
 	  break;
 
-	case '<':
-	  /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed to exist,
-	     excepting those that expand_call created.  Further, on some
-	     machines which do not have generalized auto inc/dec, an inc/dec
-	     is not a memory_operand.
-
-	     Match any memory and hope things are resolved after reload.  */
-
-	  if (MEM_P (op)
-	      && (1
-		  || GET_CODE (XEXP (op, 0)) == PRE_DEC
-		  || GET_CODE (XEXP (op, 0)) == POST_DEC))
-	    result = 1;
-#ifdef AUTO_INC_DEC
-	  incdec_ok = true;
-#endif
-	  break;
-
-	case '>':
-	  if (MEM_P (op)
-	      && (1
-		  || GET_CODE (XEXP (op, 0)) == PRE_INC
-		  || GET_CODE (XEXP (op, 0)) == POST_INC))
-	    result = 1;
-#ifdef AUTO_INC_DEC
-	  incdec_ok = true;
-#endif
-	  break;
-
-	case 'E':
-	case 'F':
-	  if (CONST_DOUBLE_AS_FLOAT_P (op) 
-	      || (GET_CODE (op) == CONST_VECTOR
-		  && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-	    result = 1;
-	  break;
-
-	case 's':
-	  if (CONST_SCALAR_INT_P (op))
-	    break;
-	  /* Fall through.  */
-
-	case 'i':
-	  if (CONSTANT_P (op) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
-	    result = 1;
-	  break;
-
-	case 'n':
-	  if (CONST_SCALAR_INT_P (op))
-	    result = 1;
-	  break;
-
-	case 'X':
-	  result = 1;
-	  break;
-
 	case 'g':
 	  if (general_operand (op, VOIDmode))
 	    result = 1;
 	  break;
 
-	case 'r':
-	reg:
-	  if (!result
-	      && GET_MODE (op) != BLKmode
-	      && register_operand (op, VOIDmode))
-	    result = 1;
-	  break;
+#ifdef AUTO_INC_DEC
+	case '<':
+	case '>':
+	  /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed
+	     to exist, excepting those that expand_call created.  Further,
+	     on some machines which do not have generalized auto inc/dec,
+	     an inc/dec is not a memory_operand.
 
+	     Match any memory and hope things are resolved after reload.  */
+	  incdec_ok = true;
+#endif
 	default:
 	  cn = lookup_constraint (constraint);
 	  switch (get_constraint_type (cn))
 	    {
 	    case CT_REGISTER:
-	      if (reg_class_for_constraint (cn) != NO_REGS)
-		goto reg;
+	      if (!result
+		  && reg_class_for_constraint (cn) != NO_REGS
+		  && GET_MODE (op) != BLKmode
+		  && register_operand (op, VOIDmode))
+		result = 1;
 	      break;
 
 	    case CT_CONST_INT:
@@ -2339,14 +2279,6 @@ preprocess_constraints (int n_operands,
 
 	      switch (c)
 		{
-		case '=': case '+': case '*': case '%':
-		case 'E': case 'F': case 'G': case 'H':
-		case 's': case 'i': case 'n':
-		case 'I': case 'J': case 'K': case 'L':
-		case 'M': case 'N': case 'O': case 'P':
-		  /* These don't say anything we care about.  */
-		  break;
-
 		case '?':
 		  op_alt[i].reject += 6;
 		  break;
@@ -2367,22 +2299,11 @@ preprocess_constraints (int n_operands,
 		  }
 		  continue;
 
-		case TARGET_MEM_CONSTRAINT:
-		  op_alt[i].memory_ok = 1;
-		  break;
 		case 'X':
 		  op_alt[i].anything_ok = 1;
 		  break;
 
-		case 'p':
-		  op_alt[i].is_address = 1;
-		  op_alt[i].cl = reg_class_subunion[(int) op_alt[i].cl]
-		      [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-					     ADDRESS, SCRATCH)];
-		  break;
-
 		case 'g':
-		case 'r':
 		  op_alt[i].cl =
 		   reg_class_subunion[(int) op_alt[i].cl][(int) GENERAL_REGS];
 		  break;
@@ -2592,10 +2513,6 @@ constrain_operands (int strict)
 		c = '\0';
 		break;
 
-	      case '?':  case '!': case '*':  case '%':
-	      case '=':  case '+':
-		break;
-
 	      case '#':
 		/* Ignore rest of this alternative as far as
 		   constraint checking is concerned.  */
@@ -2695,106 +2612,10 @@ constrain_operands (int strict)
 		  win = 1;
 		break;
 
-	      case 'X':
-		/* This is used for a MATCH_SCRATCH in the cases when
-		   we don't actually need anything.  So anything goes
-		   any time.  */
-		win = 1;
-		break;
-
-	      case TARGET_MEM_CONSTRAINT:
-		/* Memory operands must be valid, to the extent
-		   required by STRICT.  */
-		if (MEM_P (op))
-		  {
-		    if (strict > 0
-			&& !strict_memory_address_addr_space_p
-			     (GET_MODE (op), XEXP (op, 0),
-			      MEM_ADDR_SPACE (op)))
-		      break;
-		    if (strict == 0
-			&& !memory_address_addr_space_p
-			     (GET_MODE (op), XEXP (op, 0),
-			      MEM_ADDR_SPACE (op)))
-		      break;
-		    win = 1;
-		  }
-		/* Before reload, accept what reload can turn into mem.  */
-		else if (strict < 0 && CONSTANT_P (op))
-		  win = 1;
-		/* During reload, accept a pseudo  */
-		else if (reload_in_progress && REG_P (op)
-			 && REGNO (op) >= FIRST_PSEUDO_REGISTER)
-		  win = 1;
-		break;
-
-	      case '<':
-		if (MEM_P (op)
-		    && (GET_CODE (XEXP (op, 0)) == PRE_DEC
-			|| GET_CODE (XEXP (op, 0)) == POST_DEC))
-		  win = 1;
-		break;
-
-	      case '>':
-		if (MEM_P (op)
-		    && (GET_CODE (XEXP (op, 0)) == PRE_INC
-			|| GET_CODE (XEXP (op, 0)) == POST_INC))
-		  win = 1;
-		break;
-
-	      case 'E':
-	      case 'F':
-		if (CONST_DOUBLE_AS_FLOAT_P (op)
-		    || (GET_CODE (op) == CONST_VECTOR
-			&& GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-		  win = 1;
-		break;
-
-	      case 's':
-		if (CONST_SCALAR_INT_P (op))
-		  break;
-	      case 'i':
-		if (CONSTANT_P (op))
-		  win = 1;
-		break;
-
-	      case 'n':
-		if (CONST_SCALAR_INT_P (op))
-		  win = 1;
-		break;
-
-	      case 'V':
-		if (MEM_P (op)
-		    && ((strict > 0 && ! offsettable_memref_p (op))
-			|| (strict < 0
-			    && !(CONSTANT_P (op) || MEM_P (op)))
-			|| (reload_in_progress
-			    && !(REG_P (op)
-				 && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
-		  win = 1;
-		break;
-
-	      case 'o':
-		if ((strict > 0 && offsettable_memref_p (op))
-		    || (strict == 0 && offsettable_nonstrict_memref_p (op))
-		    /* Before reload, accept what reload can handle.  */
-		    || (strict < 0
-			&& (CONSTANT_P (op) || MEM_P (op)))
-		    /* During reload, accept a pseudo  */
-		    || (reload_in_progress && REG_P (op)
-			&& REGNO (op) >= FIRST_PSEUDO_REGISTER))
-		  win = 1;
-		break;
-
 	      default:
 		{
-		  enum reg_class cl;
-		  enum constraint_num cn = (c == 'r'
-					    ? CONSTRAINT__UNKNOWN
-					    : lookup_constraint (p));
-
-		  cl = (c == 'r'
-			? GENERAL_REGS : reg_class_for_constraint (cn));
+		  enum constraint_num cn = lookup_constraint (p);
+		  enum reg_class cl = reg_class_for_constraint (cn);
 		  if (cl != NO_REGS)
 		    {
 		      if (strict < 0
@@ -3227,8 +3048,7 @@ peep2_find_free_register (int from, int
       from = peep2_buf_position (from + 1);
     }
 
-  cl = (class_str[0] == 'r' ? GENERAL_REGS
-	: reg_class_for_constraint (lookup_constraint (class_str)));
+  cl = reg_class_for_constraint (lookup_constraint (class_str));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/8] Speed up lookup_constraint
  2014-06-05 21:29 ` [PATCH 2/8] Speed up lookup_constraint Richard Sandiford
@ 2014-06-10 18:41   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 18:41 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:29, Richard Sandiford wrote:
> lookup_constraint is also an out-of-line switch-based function.
> Since most constraints are still single-letter ones, it should be
> more efficient to have a lookup array for the single-character case
> and an out-of-line function for the more complicated ones.  This becomes
> even more important with the latter half of the series (which isn't as
> much of a win otherwise).
>
> Richard
>
>
> gcc/
> 	* genpreds.c (write_lookup_constraint): Rename to...
> 	(write_lookup_constraint_1): ...this.
> 	(write_lookup_constraint_array): New function.
> 	(write_tm_preds_h): Define lookup_constraint as an inline function
> 	that uses write_lookup_constraint_array where possible.
> 	(write_insn_preds_c): Update for the changes above.
OK.
Jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 3/8] Speed up constraint_satisfied_p
  2014-06-05 21:31 ` [PATCH 3/8] Speed up constraint_satisfied_p Richard Sandiford
@ 2014-06-10 18:42   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 18:42 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:30, Richard Sandiford wrote:
> After the earlier changes, the only important function that switches on
> constraint_num is constraint_satisfied_p (now constraint_satisfied_p_1).
> Since constraint_num is a dense enum, it seems faster to use a jump
> table instead.  In many cases this allows the handling function to be
> a simple sibcall to something like a predicate.
>
> Richard
>
>
> gcc/
> 	* genpreds.c (write_constraint_satisfied_p_1): Replace with...
> 	(write_constraint_satisfied_p_array): ...this new function.
> 	(write_tm_preds_h): Replace write_constraint_satisfied_p_1 with
> 	an array.
> 	(write_insn_preds_c): Update accordingly.
OK.
jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/8] Faster checks for constraint types
  2014-06-05 21:27 ` [PATCH 1/8] Faster checks for constraint types Richard Sandiford
@ 2014-06-10 18:42   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 18:42 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:26, Richard Sandiford wrote:
> genpreds.c defines routines insn_extra_memory_constraint and
> insn_extra_address_constraint for testing whether a particular
> constraint_num is a memory or address constraint.  At the moment it uses
> an out-of-line switch-based function to do this, but if we organise the
> constraint_num enum differently, we can use a simple range test instead.
>
> Similarly, if we group register constraints together, we can handle
> reg_class_for_constraint for non-register constraints inline.
> The same goes for constraint_satisfied_p and register constraints.
> The point is that constraints are either register constraints or things
> that could be satisfied by constraint_satisfied_p, never both, and
> exposing this helps with jump threading.  This becomes more important
> with the last half of the series.
>
> Richard
>
>
> gcc/
> 	* doc/md.texi (regclass_for_constraint): Rename to...
> 	(reg_class_for_constraint): ...this.
> 	* genpreds.c (num_constraints, enum_order, register_start)
> 	(register_end, satisfied_start, memory_start, memory_end)
> 	(address_start, address_end): New variables.
> 	(add_constraint): Count the number of constraints.
> 	(choose_enum_order): New function.
> 	(write_enum_constraint_num): Iterate over enum_order.
> 	(write_regclass_for_constraint): Rename to...
> 	(write_reg_class_for_constraint_1): ...this and update output
> 	accordingly.
> 	(write_constraint_satisfied_p): Rename to...
> 	(write_constraint_satisfied_p_1): ...this and update output
> 	accordingly.  Do nothing if all extra constraints are register
> 	constraints.
> 	(write_insn_extra_memory_constraint): Delete.
> 	(write_insn_extra_address_constraint): Delete.
> 	(write_range_function): New function.
> 	(write_tm_preds_h): Define constraint_satisfied_p and
> 	reg_class_for_constraint as inline functions that do a range check
> 	before calling the out-of-line function.  Use write_range_function
> 	to implement insn_extra_{register,memory,address}_constraint,
> 	the first of which is new.
> 	(write_insn_preds_c): Update after above changes to write_* functions.
> 	(main): Call choose_enum_order.
OK.
jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 5/8] Remove unused operand_alternative fields
  2014-06-05 21:33 ` [PATCH 5/8] Remove unused operand_alternative fields Richard Sandiford
@ 2014-06-10 18:43   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 18:43 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:33, Richard Sandiford wrote:
> This patch just gets rid of some write-only operand_alternative fields,
> which makes things easier for the later patches to preprocess_constraints.
>
> Richard
>
>
> gcc/
> 	* recog.h (operand_alternative): Remove offmem_ok, nonffmem_ok,
> 	decmem_ok and incmem_ok.  Reformat other bitfields for consistency.
> 	* recog.c (preprocess_constraints): Update accordingly.
OK.
Jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 6/8] Treat 'I'-'P' as separate subtype
  2014-06-05 21:38 ` [PATCH 6/8] Treat 'I'-'P' as separate subtype Richard Sandiford
@ 2014-06-10 18:48   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 18:48 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:37, Richard Sandiford wrote:
> This patch extends patch 4 to have a CT_CONST_INT type for CONST_INT
> constraints ('I'-'P'), which are already handled by things like
> constraint_satisfied_p.  On its own this has little effect, since most
> places handle 'I'-'P' as a separate case statement anyway.  It's really
> just making way for the final patch.
>
> It might be worth adding a define_const_int_constraint so that 'I'-'P'
> are less special.
>
> Richard
>
>
> gcc/
> 	* genpreds.c (const_int_start, const_int_end): New variables.
> 	(choose_enum_order): Output CONST_INT constraints before memory
> 	constraints.
> 	(write_tm_preds_h): Always define insn_const_int_ok_for_constraint.
> 	Add CT_CONST_INT.
> 	* ira-costs.c (record_reg_classes): Handle CT_CONST_INT.
> 	* ira.c (ira_setup_alts): Likewise.
> 	* lra-constraints.c (process_alt_operands): Likewise.
> 	* recog.c (asm_operand_ok, preprocess_constraints): Likewise.
> 	* reload.c (find_reloads): Likewise.
OK once prerequisites are OK'd.

Jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 7/8] Remove 'I'-'P' and 'G'/'H' cases
  2014-06-05 21:41 ` [PATCH 7/8] Remove 'I'-'P' and 'G'/'H' cases Richard Sandiford
@ 2014-06-10 18:50   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 18:50 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:41, Richard Sandiford wrote:
> After the previous patch, we can remove the separate 'I'-'P' and 'G'/'H'
> cases without increasing compile time.  I didn't bother adding the kind of
> fast-path for 'G'/'H' that I did for 'I'-'P' since it should be much rarer.
>
> This removes the last use of CONST_DOUBLE_OK_FOR_CONSTRAINT_P, so I deleted
> the code that defines it and added it to the poison list.  The only remaining
> old-style macro is CONST_INT_OK_FOR_CONSTRAINT_P, which is used by the s390
> backend.  If this series is OK I'll follow up with a patch to remove that
> usage and poison CONST_INT_OK_FOR_CONSTRAINT_P too.
>
> Richard
>
>
> gcc/
> 	* system.h (CONST_DOUBLE_OK_FOR_CONSTRAINT_P): Poison.
> 	* genpreds.c (have_const_dbl_constraints): Delete.
> 	(add_constraint): Don't set it.
> 	(write_tm_preds_h): Don't call CONST_DOUBLE_OK_FOR_CONSTRAINT_P.
> 	* ira-costs.c (record_reg_classes): Handle CONST_INT and CONST_DOUBLE
> 	constraints using the lookup_constraint logic.
> 	* ira-lives.c (single_reg_class): Likewise.
> 	* ira.c (ira_setup_alts): Likewise.
> 	* lra-constraints.c (process_alt_operands): Likewise.
> 	* recog.c (asm_operand_ok, constrain_operands): Likewise.
> 	* reload.c (find_reloads): Likewise.
OK once prerequisites have been OK'd.

Follow-up to remove last usage of CONST_INT_OK_FOR_CONSTRAINT_P 
pre-approved once prerequisites have gone in.  Just post it for archival 
purposes.

Jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 4/8] Remove old macros and make lookup_constraint explicit
  2014-06-05 21:32 ` [PATCH 4/8] Remove old macros and make lookup_constraint explicit Richard Sandiford
@ 2014-06-10 20:53   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2014-06-10 20:53 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:32, Richard Sandiford wrote:
> Now that all extra constraints are defined in .md files, there's no real
> need for the old REG_CLASS_FROM_CONSTRAINT-style macros.  The macros also
> seem dangerous performance-wise, since each one contains an embedded call to
> lookup_constraint.  This means that code like:
>
> 		    if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
> 		      {
> 			if (EXTRA_MEMORY_CONSTRAINT (c, p))
> 			  ... EXTRA_CONSTRAINT_STR ...
> 			if (EXTRA_ADDRESS_CONSTRAINT (c, p))
> 			  ... EXTRA_CONSTRAINT_STR ...
> 			... EXTRA_CONSTRAINT_STR ...
> 		      }
> 		    ...REG_CLASS_FROM_CONSTRAINT...
>
> looks up the same constraint several times.
>
> This patch replaces all uses of:
>
>      REG_CLASS_FROM_CONSTRAINT
>      REG_CLASS_FOR_CONSTRAINT
>      EXTRA_CONSTRAINT_STR
>      EXTRA_MEMORY_CONSTRAINT
>      EXTRA_ADDRESS_CONSTRAINT
>
> with separate calls to lookup_constraint and the underlying query function.
> It poisons the old macros as a way of protecting against accidental use
> (e.g. in #ifdef EXTRA_CONSTRAINT_STR blocks).
>
> Several places want to handle each specific type of constraint in a
> different way, so I added a convenience function for classifying constraints
> into a type enum.  This also makes the range checks more efficient.
> I've treated CONSTRAINT__UNKNOWN as a register constraint (the first type)
> since that avoids one more range check and means that each consumer doesn't
> have to handle non-constraints specially.  The range check in
> reg_class_for_constraint already ensures that the CONSTRAINT__UNKNOWN->
> NO_REGS mapping is inline.
>
> Richard
>
>
> gcc/
> 	* system.h (REG_CLASS_FROM_CONSTRAINT): Poison.
> 	(REG_CLASS_FOR_CONSTRAINT, EXTRA_CONSTRAINT_STR): Likewise.
> 	(EXTRA_MEMORY_CONSTRAINT, EXTRA_ADDRESS_CONSTRAINT): Likewise.
> 	* genpreds.c (print_type_tree): New function.
> 	(write_tm_preds_h): Remove REG_CLASS_FROM_CONSTRAINT,
> 	REG_CLASS_FOR_CONSTRAINT, EXTRA_MEMORY_CONSTRAINT,
> 	EXTRA_ADDRESS_CONSTRAINT and EXTRA_CONSTRAINT_STR.
> 	Write out enum constraint_type and get_constraint_type.
> 	* lra-constraints.c (satisfies_memory_constraint_p): Take a
> 	constraint_num rather than a constraint string.
> 	(satisfies_address_constraint_p): Likewise.
> 	(reg_class_from_constraints): Avoid old constraint macros.
> 	(process_alt_operands, process_address_1): Likewise.
> 	(curr_insn_transform): Likewise.
> 	* ira-costs.c (record_reg_classes): Likewise.
> 	(record_operand_costs): Likewise.
> 	* ira-lives.c (single_reg_class): Likewise.
> 	(ira_implicitly_set_insn_hard_regs): Likewise.
> 	* ira.c (ira_setup_alts, ira_get_dup_out_num): Likewise.
> 	* postreload.c (reload_cse_simplify_operands): Likewise.
> 	* recog.c (asm_operand_ok, preprocess_constraints): Likewise.
> 	(constrain_operands, peep2_find_free_register): Likewise.
> 	* reload.c (push_secondary_reload, scratch_reload_class): Likewise.
> 	(find_reloads, alternative_allows_const_pool_ref): Likewise.
> 	* reload1.c (maybe_fix_stack_asms): Likewise.
> 	* stmt.c (parse_output_constraint, parse_input_constraint): Likewise.
> 	* targhooks.c (default_secondary_reload): Likewise.
> 	* config/m32c/m32c.c (m32c_matches_constraint_p): Avoid reference
> 	to EXTRA_CONSTRAINT_STR.
> 	* config/sparc/constraints.md (U): Likewise REG_CLASS_FROM_CONSTRAINT.
Given the level of testing you've done, I only spot checked a few places 
after concluding the general direction you were going makes sense.  I 
don't expect any fallout, but I'm confident you'll deal with it if it 
happens.

Thanks.  OK for the trunk,

Jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-05 21:43 ` [PATCH 8/8] Add a common .md file and define standard constraints there Richard Sandiford
@ 2014-06-10 20:59   ` Jeff Law
  2014-06-11 17:01     ` Richard Sandiford
  2014-06-12 19:24   ` Segher Boessenkool
  1 sibling, 1 reply; 25+ messages in thread
From: Jeff Law @ 2014-06-10 20:59 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On 06/05/14 15:43, Richard Sandiford wrote:
> This final patch uses a common .md file to define all standard
> constraints except 'g'.  It then gets rid of explicit case statements
> for the standard constraints, except in two cases:
>
> (1) recog.c:asm_operand_ok still needs to handle 'o' specially for
>      targets like ia64 that don't have offsettable addresses.  See the
>      comment there for justification.
>
> (2) the trickier cases in reload.  I'm not changing those more than I have to.
Can't argue with #2 ;-)  reload gets less and less important every day, 
so I see less and less value hacking too much on it.

>
> I did wonder about defining a new rtl construct that could be used for 'g',
> so that even that special case goes away.  In the end I think it would be
> a false abstraction though.  No other constraint allows (or IMO should allow)
> all three of a register class, a base-reloadable memory and a constant,
> so handling it in the lookup_constraint paths would make things more
> complicated rather than less.
OK.

>
> Note that the s390 'e' constraint is TARGET_MEM_CONSTRAINT, which is now
> defined in the common file.
>
> I put the common .md file in the main gcc/ directory by analogy with
> defaults.h and common.opt.  It could instead go in config/ or config/common/,
> if those sound better.
Seems fine to me, I don't feel a need to bikeshed here.


Does the comment before indep_constraints in genoutput need updating? 
The constraints in common.md are machine independent, but aren't listed 
in indep_constraints in genoutput.c

Approved with whatever language you want to use for that comment.

Jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-10 20:59   ` Jeff Law
@ 2014-06-11 17:01     ` Richard Sandiford
  2014-06-13 20:06       ` Steve Ellcey
  0 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-11 17:01 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches

Thanks for the reviews.

Jeff Law <law@redhat.com> writes:
> Does the comment before indep_constraints in genoutput need updating? 
> The constraints in common.md are machine independent, but aren't listed 
> in indep_constraints in genoutput.c

Yeah, good catch.  I changed it to:

/* All machine-independent constraint characters (except digits) that
   are handled outside the define*_constraint mechanism.  */
static const char indep_constraints[] = ",=+%*?!#&g";

Also in genpreds.c:

/* Contraint letters that have a special meaning and that cannot be used
   in define*_constraints.  */
static const char generic_constraint_letters[] = "g";

Richard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-05 21:43 ` [PATCH 8/8] Add a common .md file and define standard constraints there Richard Sandiford
  2014-06-10 20:59   ` Jeff Law
@ 2014-06-12 19:24   ` Segher Boessenkool
  2014-06-12 19:39     ` Paul_Koning
  1 sibling, 1 reply; 25+ messages in thread
From: Segher Boessenkool @ 2014-06-12 19:24 UTC (permalink / raw)
  To: gcc-patches, rdsandiford

On Thu, Jun 05, 2014 at 10:43:25PM +0100, Richard Sandiford wrote:
> This final patch uses a common .md file to define all standard
> constraints except 'g'.

I had a look at what targets still use "g".  Note: there can be
errors in this, it's all based on  \<g[,"]  :-)

* frv and mcore use "g" in commented-out patterns;
* cr16, mcore, picochip, rl78, and sh use "g" where they mean "rm"
  or "m";
* m68k uses it (in a dbne pattern) where the C template splits
  the "r", "m", "i" cases again;
* bfin, fr30, h8300, m68k, rs6000, and v850 use it as the second
  operand (# bytes pushed) of the call patterns; that operand is
  unused in all these cases, could just be "";
* cris, m68k, pdp11, and vax actually use "g".

So it won't be all that much work to completely get rid of "g".
Do we want that?


Segher

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-12 19:24   ` Segher Boessenkool
@ 2014-06-12 19:39     ` Paul_Koning
  2014-06-12 21:19       ` Segher Boessenkool
  0 siblings, 1 reply; 25+ messages in thread
From: Paul_Koning @ 2014-06-12 19:39 UTC (permalink / raw)
  To: segher; +Cc: gcc-patches, rdsandiford


On Jun 12, 2014, at 3:24 PM, Segher Boessenkool <segher@kernel.crashing.org> wrote:

> On Thu, Jun 05, 2014 at 10:43:25PM +0100, Richard Sandiford wrote:
>> This final patch uses a common .md file to define all standard
>> constraints except 'g'.
> 
> I had a look at what targets still use "g".  Note: there can be
> errors in this, it's all based on  \<g[,"]  :-)
> 
> * frv and mcore use "g" in commented-out patterns;
> * cr16, mcore, picochip, rl78, and sh use "g" where they mean "rm"
>  or "m";
> * m68k uses it (in a dbne pattern) where the C template splits
>  the "r", "m", "i" cases again;
> * bfin, fr30, h8300, m68k, rs6000, and v850 use it as the second
>  operand (# bytes pushed) of the call patterns; that operand is
>  unused in all these cases, could just be "";
> * cris, m68k, pdp11, and vax actually use "g".
> 
> So it won't be all that much work to completely get rid of "g".
> Do we want that?

Is it simply a matter of replacing “g” by “mri”?  That’s what the doc suggests.  Or is there more to the story than that?

	paul

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-12 19:39     ` Paul_Koning
@ 2014-06-12 21:19       ` Segher Boessenkool
  2014-06-14  9:58         ` Richard Sandiford
  0 siblings, 1 reply; 25+ messages in thread
From: Segher Boessenkool @ 2014-06-12 21:19 UTC (permalink / raw)
  To: Paul_Koning; +Cc: gcc-patches, rdsandiford

> > * cris, m68k, pdp11, and vax actually use "g".
> > 
> > So it won't be all that much work to completely get rid of "g".
> > Do we want that?
> 
> Is it simply a matter of replacing “g” by “mri”?  That’s what the doc suggests.  Or is there more to the story than that?

As far as I know "g" and "rmi" are equivalent, yes.  "g" is easier to
type and read if you use it a lot (only ancient targets really); the
compiler will probably become somewhat slower for those targets, and
perhaps somewhat faster for all others.  Hard to say without doing the
work and measuring the result :-)


Segher

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-11 17:01     ` Richard Sandiford
@ 2014-06-13 20:06       ` Steve Ellcey
  2014-06-14  7:49         ` Richard Sandiford
  0 siblings, 1 reply; 25+ messages in thread
From: Steve Ellcey @ 2014-06-13 20:06 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 880 bytes --]

Richard,

Something in these constraint patches broke my mips16 build (I cannot
build glibc in mips16 mode).  I have cut down a test case and verified
that the problem started with this checkin:

2014-06-11  Richard Sandiford  <rdsandiford@googlemail.com>

	* common.md: New file.
	* doc/md.texi: Update description of generic, machine-independent
	constraints.
	* config/s390/constraints.md (e): Delete.
	* Makefile.in (md_file): Include common.md.
	* config/m32c/t-m32c (md_file): Likewise.
	* genpreds.c (general_mem): New array.
	(etc)

Attached is a small test case (its ugly but it comes from vfscanf in glibc) that
fails to compile for me with these options:

  -mips32r2 -mips16 -mabi=32 -std=gnu99 -fgnu89-inline -O2 -c x.c

Error message:

/tmp/ccAltddb.s: Assembler messages:
/tmp/ccAltddb.s:23: Error: invalid operands `sb $3,24($sp)'


Steve Ellcey
sellcey@mips.com


[-- Attachment #2: x.c --]
[-- Type: text/x-csrc, Size: 978 bytes --]

extern long long __mips16_syscall4(long, long, long, long, long);
typedef unsigned int size_t;
 union __mips16_syscall_return   {
     long long val;
 };
 typedef struct {
 int lock;
 }
 _IO_lock_t;
 struct _IO_FILE {
   _IO_lock_t *_lock;
 };
 typedef struct _IO_FILE _IO_FILE;
int  _IO_vfscanf_internal (_IO_FILE *s) {
   int c = 0;
   char *wp = ((void *)0);
   size_t wpsize;
   wp = (char *) (__typeof (wp)) ({
	size_t __newlen = 32; /* (((newsize * sizeof (char)) + 15) & -16); */
	char *__newbuf = __builtin_alloca (__newlen);
 	__newbuf;
 	}
);
 wp[wpsize++] = (c);
 ((void) ({
 int *__futex = (&((*(s)->_lock).lock));
 int __val = ({
 	__typeof (*__futex) __atg1_result;
 	__atg1_result;
 	}
);
 if (__builtin_expect (__val > 1, 0)) ({
 long int __ret;
 __ret = ({
     union __mips16_syscall_return ret;
     ret.val = __mips16_syscall4 ((long) ((long) (__futex)), (long) (((1) | 128)), (long) ((1)), (long) (0), (long) ((4000 + 238)));
          }
);
 }
);
 }
));
 }

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-13 20:06       ` Steve Ellcey
@ 2014-06-14  7:49         ` Richard Sandiford
  2014-06-16 14:48           ` Steve Ellcey
  0 siblings, 1 reply; 25+ messages in thread
From: Richard Sandiford @ 2014-06-14  7:49 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: gcc-patches

Steve Ellcey <sellcey@mips.com> writes:
> Richard,
>
> Something in these constraint patches broke my mips16 build (I cannot
> build glibc in mips16 mode).  I have cut down a test case and verified
> that the problem started with this checkin:
>
> 2014-06-11  Richard Sandiford  <rdsandiford@googlemail.com>
>
> 	* common.md: New file.
> 	* doc/md.texi: Update description of generic, machine-independent
> 	constraints.
> 	* config/s390/constraints.md (e): Delete.
> 	* Makefile.in (md_file): Include common.md.
> 	* config/m32c/t-m32c (md_file): Likewise.
> 	* genpreds.c (general_mem): New array.
> 	(etc)
>
> Attached is a small test case (its ugly but it comes from vfscanf in glibc) that
> fails to compile for me with these options:
>
>   -mips32r2 -mips16 -mabi=32 -std=gnu99 -fgnu89-inline -O2 -c x.c
>
> Error message:
>
> /tmp/ccAltddb.s: Assembler messages:
> /tmp/ccAltddb.s:23: Error: invalid operands `sb $3,24($sp)'

The problem here is that mips_regno_mode_ok_for_base_p allows invalid
hard registers as bases if !strict_p.  It was always a bit of a hack
and the reason it was added no longer applies.  Robert's LRA patch
already included a fix, so maybe we should just apply that part now.

The patch below fixes the testcase.  Please could you give it a spin
and see whether there's any other fallout?  I assume this would have
shown up in a testsuite run if you'd been able to get that far.

Thanks,
Richard


2014-03-26  Robert Suchanek  <Robert.Suchanek@imgtec.com>

	* config/mips/mips.c (mips_regno_mode_ok_for_base_p): Remove use
	!strict_p for MIPS16.

diff --git gcc/config/mips/mips.c gcc/config/mips/mips.c
index 45256e9..81b6c26 100644
--- gcc/config/mips/mips.c
+++ gcc/config/mips/mips.c
@@ -2241,22 +2241,9 @@ mips_regno_mode_ok_for_base_p (int regno, enum machine_mode mode,
     return true;
 
   /* In MIPS16 mode, the stack pointer can only address word and doubleword
-     values, nothing smaller.  There are two problems here:
-
-       (a) Instantiating virtual registers can introduce new uses of the
-	   stack pointer.  If these virtual registers are valid addresses,
-	   the stack pointer should be too.
-
-       (b) Most uses of the stack pointer are not made explicit until
-	   FRAME_POINTER_REGNUM and ARG_POINTER_REGNUM have been eliminated.
-	   We don't know until that stage whether we'll be eliminating to the
-	   stack pointer (which needs the restriction) or the hard frame
-	   pointer (which doesn't).
-
-     All in all, it seems more consistent to only enforce this restriction
-     during and after reload.  */
+     values, nothing smaller.  */
   if (TARGET_MIPS16 && regno == STACK_POINTER_REGNUM)
-    return !strict_p || GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8;
+    return GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8;
 
   return TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno);
 }
l

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-12 21:19       ` Segher Boessenkool
@ 2014-06-14  9:58         ` Richard Sandiford
  0 siblings, 0 replies; 25+ messages in thread
From: Richard Sandiford @ 2014-06-14  9:58 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: Paul_Koning, gcc-patches

Segher Boessenkool <segher@kernel.crashing.org> writes:
>> > * cris, m68k, pdp11, and vax actually use "g".
>> > 
>> > So it won't be all that much work to completely get rid of "g".
>> > Do we want that?
>> 
>> Is it simply a matter of replacing “g” by “mri”?  That’s what the doc
>> suggests.  Or is there more to the story than that?
>
> As far as I know "g" and "rmi" are equivalent, yes.  "g" is easier to
> type and read if you use it a lot (only ancient targets really); the
> compiler will probably become somewhat slower for those targets, and
> perhaps somewhat faster for all others.  Hard to say without doing the
> work and measuring the result :-)

FWIW, I had a follow-on patch that created the recog_op_alt data at
build time and made the constraints field of that structure point to
CONSTRAINT_* bytes rather than raw strings.  That involved converting
"g" to "rmi" like you say and also meant adding CONSTRAINT_*s for "#"
and "?".  (Other non-operand characters can be dropped since the information
is given directly in the recog_op_alt.)

It didn't really seem to be much of a win though.

Richard

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 8/8] Add a common .md file and define standard constraints there
  2014-06-14  7:49         ` Richard Sandiford
@ 2014-06-16 14:48           ` Steve Ellcey
  0 siblings, 0 replies; 25+ messages in thread
From: Steve Ellcey @ 2014-06-16 14:48 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches

On Sat, 2014-06-14 at 08:49 +0100, Richard Sandiford wrote:

> The patch below fixes the testcase.  Please could you give it a spin
> and see whether there's any other fallout?  I assume this would have
> shown up in a testsuite run if you'd been able to get that far.
> 
> Thanks,
> Richard

The patch fixed my build and the testsuite results looked good too.

Steve Ellcey
sellcey@mips.com

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2014-06-16 14:48 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-05 21:25 [PATCH 0/8] Constraint matching TLC Richard Sandiford
2014-06-05 21:27 ` [PATCH 1/8] Faster checks for constraint types Richard Sandiford
2014-06-10 18:42   ` Jeff Law
2014-06-05 21:29 ` [PATCH 2/8] Speed up lookup_constraint Richard Sandiford
2014-06-10 18:41   ` Jeff Law
2014-06-05 21:31 ` [PATCH 3/8] Speed up constraint_satisfied_p Richard Sandiford
2014-06-10 18:42   ` Jeff Law
2014-06-05 21:32 ` [PATCH 4/8] Remove old macros and make lookup_constraint explicit Richard Sandiford
2014-06-10 20:53   ` Jeff Law
2014-06-05 21:33 ` [PATCH 5/8] Remove unused operand_alternative fields Richard Sandiford
2014-06-10 18:43   ` Jeff Law
2014-06-05 21:38 ` [PATCH 6/8] Treat 'I'-'P' as separate subtype Richard Sandiford
2014-06-10 18:48   ` Jeff Law
2014-06-05 21:41 ` [PATCH 7/8] Remove 'I'-'P' and 'G'/'H' cases Richard Sandiford
2014-06-10 18:50   ` Jeff Law
2014-06-05 21:43 ` [PATCH 8/8] Add a common .md file and define standard constraints there Richard Sandiford
2014-06-10 20:59   ` Jeff Law
2014-06-11 17:01     ` Richard Sandiford
2014-06-13 20:06       ` Steve Ellcey
2014-06-14  7:49         ` Richard Sandiford
2014-06-16 14:48           ` Steve Ellcey
2014-06-12 19:24   ` Segher Boessenkool
2014-06-12 19:39     ` Paul_Koning
2014-06-12 21:19       ` Segher Boessenkool
2014-06-14  9:58         ` Richard Sandiford

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).