Blame SOURCES/gcc5-pr65689.patch

1fb7ed
2015-04-17  Jakub Jelinek  <jakub@redhat.com>
1fb7ed
1fb7ed
	PR target/65689
1fb7ed
	* genpreds.c (struct constraint_data): Add maybe_allows_reg and
1fb7ed
	maybe_allows_mem bitfields.
1fb7ed
	(maybe_allows_none_start, maybe_allows_none_end,
1fb7ed
	maybe_allows_reg_start, maybe_allows_reg_end, maybe_allows_mem_start,
1fb7ed
	maybe_allows_mem_end): New variables.
1fb7ed
	(compute_maybe_allows): New function.
1fb7ed
	(add_constraint): Use it to initialize maybe_allows_reg and
1fb7ed
	maybe_allows_mem fields.
1fb7ed
	(choose_enum_order): Sort the non-is_register/is_const_int/is_memory/
1fb7ed
	is_address constraints such that those that allow neither mem nor
1fb7ed
	reg come first, then those that only allow reg but not mem, then
1fb7ed
	those that only allow mem but not reg, then the rest.
1fb7ed
	(write_allows_reg_mem_function): New function.
1fb7ed
	(write_tm_preds_h): Call it.
1fb7ed
	* stmt.c (parse_output_constraint, parse_input_constraint): Use
1fb7ed
	the generated insn_extra_constraint_allows_reg_mem function
1fb7ed
	instead of always setting *allows_reg = true; *allows_mem = true;
1fb7ed
	for unknown extra constraints.
1fb7ed
1fb7ed
	* gcc.target/aarch64/c-output-template-4.c: New test.
1fb7ed
1fb7ed
--- gcc/genpreds.c.jj	2015-04-08 18:23:50.643556230 +0200
1fb7ed
+++ gcc/genpreds.c	2015-04-17 17:44:23.097650110 +0200
1fb7ed
@@ -640,12 +640,14 @@ struct constraint_data
1fb7ed
   const char *regclass;  /* for register constraints */
1fb7ed
   rtx exp;               /* for other constraints */
1fb7ed
   unsigned int lineno;   /* line of definition */
1fb7ed
-  unsigned int is_register  : 1;
1fb7ed
-  unsigned int is_const_int : 1;
1fb7ed
-  unsigned int is_const_dbl : 1;
1fb7ed
-  unsigned int is_extra     : 1;
1fb7ed
-  unsigned int is_memory    : 1;
1fb7ed
-  unsigned int is_address   : 1;
1fb7ed
+  unsigned int is_register	: 1;
1fb7ed
+  unsigned int is_const_int	: 1;
1fb7ed
+  unsigned int is_const_dbl	: 1;
1fb7ed
+  unsigned int is_extra		: 1;
1fb7ed
+  unsigned int is_memory	: 1;
1fb7ed
+  unsigned int is_address	: 1;
1fb7ed
+  unsigned int maybe_allows_reg : 1;
1fb7ed
+  unsigned int maybe_allows_mem : 1;
1fb7ed
 };
1fb7ed
 
1fb7ed
 /* Overview of all constraints beginning with a given letter.  */
1fb7ed
@@ -691,6 +693,9 @@ static unsigned int satisfied_start;
1fb7ed
 static unsigned int const_int_start, const_int_end;
1fb7ed
 static unsigned int memory_start, memory_end;
1fb7ed
 static unsigned int address_start, address_end;
1fb7ed
+static unsigned int maybe_allows_none_start, maybe_allows_none_end;
1fb7ed
+static unsigned int maybe_allows_reg_start, maybe_allows_reg_end;
1fb7ed
+static unsigned int maybe_allows_mem_start, maybe_allows_mem_end;
1fb7ed
 
1fb7ed
 /* Convert NAME, which contains angle brackets and/or underscores, to
1fb7ed
    a string that can be used as part of a C identifier.  The string
1fb7ed
@@ -711,6 +716,34 @@ mangle (const char *name)
1fb7ed
   return XOBFINISH (rtl_obstack, const char *);
1fb7ed
 }
1fb7ed
 
1fb7ed
+/* Return a bitmask, bit 1 if EXP maybe allows a REG/SUBREG, 2 if EXP
1fb7ed
+   maybe allows a MEM.  Bits should be clear only when we are sure it
1fb7ed
+   will not allow a REG/SUBREG or a MEM.  */
1fb7ed
+static int
1fb7ed
+compute_maybe_allows (rtx exp)
1fb7ed
+{
1fb7ed
+  switch (GET_CODE (exp))
1fb7ed
+    {
1fb7ed
+    case IF_THEN_ELSE:
1fb7ed
+      /* Conservative answer is like IOR, of the THEN and ELSE branches.  */
1fb7ed
+      return compute_maybe_allows (XEXP (exp, 1))
1fb7ed
+	     | compute_maybe_allows (XEXP (exp, 2));
1fb7ed
+    case AND:
1fb7ed
+      return compute_maybe_allows (XEXP (exp, 0))
1fb7ed
+	     & compute_maybe_allows (XEXP (exp, 1));
1fb7ed
+    case IOR:
1fb7ed
+      return compute_maybe_allows (XEXP (exp, 0))
1fb7ed
+	     | compute_maybe_allows (XEXP (exp, 1));
1fb7ed
+    case MATCH_CODE:
1fb7ed
+      if (*XSTR (exp, 1) == '\0')
1fb7ed
+	return (strstr (XSTR (exp, 0), "reg") != NULL ? 1 : 0)
1fb7ed
+	       | (strstr (XSTR (exp, 0), "mem") != NULL ? 2 : 0);
1fb7ed
+      /* FALLTHRU */
1fb7ed
+    default:
1fb7ed
+      return 3;
1fb7ed
+    }
1fb7ed
+}
1fb7ed
+
1fb7ed
 /* Add one constraint, of any sort, to the tables.  NAME is its name;
1fb7ed
    REGCLASS is the register class, if any; EXP is the expression to
1fb7ed
    test, if any;  IS_MEMORY and IS_ADDRESS indicate memory and address
1fb7ed
@@ -866,6 +899,11 @@ add_constraint (const char *name, const
1fb7ed
   c->is_extra = !(regclass || is_const_int || is_const_dbl);
1fb7ed
   c->is_memory = is_memory;
1fb7ed
   c->is_address = is_address;
1fb7ed
+  int maybe_allows = 3;
1fb7ed
+  if (exp)
1fb7ed
+    maybe_allows = compute_maybe_allows (exp);
1fb7ed
+  c->maybe_allows_reg = (maybe_allows & 1) != 0;
1fb7ed
+  c->maybe_allows_mem = (maybe_allows & 2) != 0;
1fb7ed
 
1fb7ed
   c->next_this_letter = *slot;
1fb7ed
   *slot = c;
1fb7ed
@@ -940,8 +978,30 @@ choose_enum_order (void)
1fb7ed
       enum_order[next++] = c;
1fb7ed
   address_end = next;
1fb7ed
 
1fb7ed
+  maybe_allows_none_start = next;
1fb7ed
+  FOR_ALL_CONSTRAINTS (c)
1fb7ed
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
1fb7ed
+	&& !c->maybe_allows_reg && !c->maybe_allows_mem)
1fb7ed
+      enum_order[next++] = c;
1fb7ed
+  maybe_allows_none_end = next;
1fb7ed
+
1fb7ed
+  maybe_allows_reg_start = next;
1fb7ed
+  FOR_ALL_CONSTRAINTS (c)
1fb7ed
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
1fb7ed
+	&& c->maybe_allows_reg && !c->maybe_allows_mem)
1fb7ed
+      enum_order[next++] = c;
1fb7ed
+  maybe_allows_reg_end = next;
1fb7ed
+
1fb7ed
+  maybe_allows_mem_start = next;
1fb7ed
+  FOR_ALL_CONSTRAINTS (c)
1fb7ed
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
1fb7ed
+	&& !c->maybe_allows_reg && c->maybe_allows_mem)
1fb7ed
+      enum_order[next++] = c;
1fb7ed
+  maybe_allows_mem_end = next;
1fb7ed
+
1fb7ed
   FOR_ALL_CONSTRAINTS (c)
1fb7ed
-    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address)
1fb7ed
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
1fb7ed
+	&& c->maybe_allows_reg && c->maybe_allows_mem)
1fb7ed
       enum_order[next++] = c;
1fb7ed
   gcc_assert (next == num_constraints);
1fb7ed
 }
1fb7ed
@@ -1229,6 +1289,41 @@ write_range_function (const char *name,
1fb7ed
 	    "}\n\n", name);
1fb7ed
 }
1fb7ed
 
1fb7ed
+/* Write a definition for insn_extra_constraint_allows_reg_mem function.  */
1fb7ed
+static void
1fb7ed
+write_allows_reg_mem_function (void)
1fb7ed
+{
1fb7ed
+  printf ("static inline void\n"
1fb7ed
+	  "insn_extra_constraint_allows_reg_mem (enum constraint_num c,\n"
1fb7ed
+	  "\t\t\t\t      bool *allows_reg, bool *allows_mem)\n"
1fb7ed
+	  "{\n");
1fb7ed
+  if (maybe_allows_none_start != maybe_allows_none_end)
1fb7ed
+    printf ("  if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n"
1fb7ed
+	    "    return;\n",
1fb7ed
+	    enum_order[maybe_allows_none_start]->c_name,
1fb7ed
+	    enum_order[maybe_allows_none_end - 1]->c_name);
1fb7ed
+  if (maybe_allows_reg_start != maybe_allows_reg_end)
1fb7ed
+    printf ("  if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n"
1fb7ed
+	    "    {\n"
1fb7ed
+	    "      *allows_reg = true;\n"
1fb7ed
+	    "      return;\n"
1fb7ed
+	    "    }\n",
1fb7ed
+	    enum_order[maybe_allows_reg_start]->c_name,
1fb7ed
+	    enum_order[maybe_allows_reg_end - 1]->c_name);
1fb7ed
+  if (maybe_allows_mem_start != maybe_allows_mem_end)
1fb7ed
+    printf ("  if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n"
1fb7ed
+	    "    {\n"
1fb7ed
+	    "      *allows_mem = true;\n"
1fb7ed
+	    "      return;\n"
1fb7ed
+	    "    }\n",
1fb7ed
+	    enum_order[maybe_allows_mem_start]->c_name,
1fb7ed
+	    enum_order[maybe_allows_mem_end - 1]->c_name);
1fb7ed
+  printf ("  (void) c;\n"
1fb7ed
+	  "  *allows_reg = true;\n"
1fb7ed
+	  "  *allows_mem = true;\n"
1fb7ed
+	  "}\n\n");
1fb7ed
+}
1fb7ed
+
1fb7ed
 /* VEC is a list of key/value pairs, with the keys being lower bounds
1fb7ed
    of a range.  Output a decision tree that handles the keys covered by
1fb7ed
    [VEC[START], VEC[END]), returning FALLBACK for keys lower then VEC[START]'s.
1fb7ed
@@ -1326,6 +1421,7 @@ write_tm_preds_h (void)
1fb7ed
 			    memory_start, memory_end);
1fb7ed
       write_range_function ("insn_extra_address_constraint",
1fb7ed
 			    address_start, address_end);
1fb7ed
+      write_allows_reg_mem_function ();
1fb7ed
 
1fb7ed
       if (constraint_max_namelen > 1)
1fb7ed
         {
1fb7ed
--- gcc/stmt.c.jj	2015-04-08 18:23:50.660555956 +0200
1fb7ed
+++ gcc/stmt.c	2015-04-17 17:36:50.623044548 +0200
1fb7ed
@@ -342,13 +342,7 @@ parse_output_constraint (const char **co
1fb7ed
 	else if (insn_extra_memory_constraint (cn))
1fb7ed
 	  *allows_mem = true;
1fb7ed
 	else
1fb7ed
-	  {
1fb7ed
-	    /* Otherwise we can't assume anything about the nature of
1fb7ed
-	       the constraint except that it isn't purely registers.
1fb7ed
-	       Treat it like "g" and hope for the best.  */
1fb7ed
-	    *allows_reg = true;
1fb7ed
-	    *allows_mem = true;
1fb7ed
-	  }
1fb7ed
+	  insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
1fb7ed
 	break;
1fb7ed
       }
1fb7ed
 
1fb7ed
@@ -465,13 +459,7 @@ parse_input_constraint (const char **con
1fb7ed
 	else if (insn_extra_memory_constraint (cn))
1fb7ed
 	  *allows_mem = true;
1fb7ed
 	else
1fb7ed
-	  {
1fb7ed
-	    /* Otherwise we can't assume anything about the nature of
1fb7ed
-	       the constraint except that it isn't purely registers.
1fb7ed
-	       Treat it like "g" and hope for the best.  */
1fb7ed
-	    *allows_reg = true;
1fb7ed
-	    *allows_mem = true;
1fb7ed
-	  }
1fb7ed
+	  insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
1fb7ed
 	break;
1fb7ed
       }
1fb7ed
 
1fb7ed
--- gcc/testsuite/gcc.target/aarch64/c-output-template-4.c.jj	2015-04-17 17:48:27.588654584 +0200
1fb7ed
+++ gcc/testsuite/gcc.target/aarch64/c-output-template-4.c	2015-04-17 17:48:22.149743468 +0200
1fb7ed
@@ -0,0 +1,10 @@
1fb7ed
+/* { dg-do compile } */
1fb7ed
+/* { dg-options "-O0" } */
1fb7ed
+
1fb7ed
+void
1fb7ed
+test (void)
1fb7ed
+{
1fb7ed
+    __asm__ ("@ %c0" : : "S" (&test + 4));
1fb7ed
+}
1fb7ed
+
1fb7ed
+/* { dg-final { scan-assembler "@ test\\+4" } } */