re PR target/65689 ([AArch64] S constraint fails for inline asm at -O0)
authorJakub Jelinek <jakub@redhat.com>
Fri, 17 Apr 2015 16:43:28 +0000 (18:43 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 17 Apr 2015 16:43:28 +0000 (18:43 +0200)
PR target/65689
* genpreds.c (struct constraint_data): Add maybe_allows_reg and
maybe_allows_mem bitfields.
(maybe_allows_none_start, maybe_allows_none_end,
maybe_allows_reg_start, maybe_allows_reg_end, maybe_allows_mem_start,
maybe_allows_mem_end): New variables.
(compute_maybe_allows): New function.
(add_constraint): Use it to initialize maybe_allows_reg and
maybe_allows_mem fields.
(choose_enum_order): Sort the non-is_register/is_const_int/is_memory/
is_address constraints such that those that allow neither mem nor
reg come first, then those that only allow reg but not mem, then
those that only allow mem but not reg, then the rest.
(write_allows_reg_mem_function): New function.
(write_tm_preds_h): Call it.
* stmt.c (parse_output_constraint, parse_input_constraint): Use
the generated insn_extra_constraint_allows_reg_mem function
instead of always setting *allows_reg = true; *allows_mem = true;
for unknown extra constraints.

* gcc.target/aarch64/c-output-template-4.c: New test.

From-SVN: r222186

gcc/ChangeLog
gcc/genpreds.c
gcc/stmt.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/c-output-template-4.c [new file with mode: 0644]

index 71c692e91a038c733c5ceeded8229fa944acc516..8cbf7c69eafa99c301b8bad38e37b6554a4e235a 100644 (file)
@@ -1,3 +1,25 @@
+2015-04-17  Jakub Jelinek  <jakub@redhat.com>
+
+       PR target/65689
+       * genpreds.c (struct constraint_data): Add maybe_allows_reg and
+       maybe_allows_mem bitfields.
+       (maybe_allows_none_start, maybe_allows_none_end,
+       maybe_allows_reg_start, maybe_allows_reg_end, maybe_allows_mem_start,
+       maybe_allows_mem_end): New variables.
+       (compute_maybe_allows): New function.
+       (add_constraint): Use it to initialize maybe_allows_reg and
+       maybe_allows_mem fields.
+       (choose_enum_order): Sort the non-is_register/is_const_int/is_memory/
+       is_address constraints such that those that allow neither mem nor
+       reg come first, then those that only allow reg but not mem, then
+       those that only allow mem but not reg, then the rest.
+       (write_allows_reg_mem_function): New function.
+       (write_tm_preds_h): Call it.
+       * stmt.c (parse_output_constraint, parse_input_constraint): Use
+       the generated insn_extra_constraint_allows_reg_mem function
+       instead of always setting *allows_reg = true; *allows_mem = true;
+       for unknown extra constraints.
+
 2015-04-17  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/65780
index 1eb3368cf645e7dc54a75658d67b8748ed395f8e..1dcb76936eb9f01918ddcd32b15d5f99cdec28ef 100644 (file)
@@ -640,12 +640,14 @@ struct constraint_data
   const char *regclass;  /* for register constraints */
   rtx exp;               /* for other constraints */
   unsigned int lineno;   /* line of definition */
-  unsigned int is_register  : 1;
-  unsigned int is_const_int : 1;
-  unsigned int is_const_dbl : 1;
-  unsigned int is_extra     : 1;
-  unsigned int is_memory    : 1;
-  unsigned int is_address   : 1;
+  unsigned int is_register     : 1;
+  unsigned int is_const_int    : 1;
+  unsigned int is_const_dbl    : 1;
+  unsigned int is_extra                : 1;
+  unsigned int is_memory       : 1;
+  unsigned int is_address      : 1;
+  unsigned int maybe_allows_reg : 1;
+  unsigned int maybe_allows_mem : 1;
 };
 
 /* Overview of all constraints beginning with a given letter.  */
@@ -691,6 +693,9 @@ 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;
+static unsigned int maybe_allows_none_start, maybe_allows_none_end;
+static unsigned int maybe_allows_reg_start, maybe_allows_reg_end;
+static unsigned int maybe_allows_mem_start, maybe_allows_mem_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
@@ -711,6 +716,34 @@ mangle (const char *name)
   return XOBFINISH (rtl_obstack, const char *);
 }
 
+/* Return a bitmask, bit 1 if EXP maybe allows a REG/SUBREG, 2 if EXP
+   maybe allows a MEM.  Bits should be clear only when we are sure it
+   will not allow a REG/SUBREG or a MEM.  */
+static int
+compute_maybe_allows (rtx exp)
+{
+  switch (GET_CODE (exp))
+    {
+    case IF_THEN_ELSE:
+      /* Conservative answer is like IOR, of the THEN and ELSE branches.  */
+      return compute_maybe_allows (XEXP (exp, 1))
+            | compute_maybe_allows (XEXP (exp, 2));
+    case AND:
+      return compute_maybe_allows (XEXP (exp, 0))
+            & compute_maybe_allows (XEXP (exp, 1));
+    case IOR:
+      return compute_maybe_allows (XEXP (exp, 0))
+            | compute_maybe_allows (XEXP (exp, 1));
+    case MATCH_CODE:
+      if (*XSTR (exp, 1) == '\0')
+       return (strstr (XSTR (exp, 0), "reg") != NULL ? 1 : 0)
+              | (strstr (XSTR (exp, 0), "mem") != NULL ? 2 : 0);
+      /* FALLTHRU */
+    default:
+      return 3;
+    }
+}
+
 /* Add one constraint, of any sort, to the tables.  NAME is its name;
    REGCLASS is the register class, if any; EXP is the expression to
    test, if any;  IS_MEMORY and IS_ADDRESS indicate memory and address
@@ -866,6 +899,11 @@ add_constraint (const char *name, const char *regclass,
   c->is_extra = !(regclass || is_const_int || is_const_dbl);
   c->is_memory = is_memory;
   c->is_address = is_address;
+  int maybe_allows = 3;
+  if (exp)
+    maybe_allows = compute_maybe_allows (exp);
+  c->maybe_allows_reg = (maybe_allows & 1) != 0;
+  c->maybe_allows_mem = (maybe_allows & 2) != 0;
 
   c->next_this_letter = *slot;
   *slot = c;
@@ -940,8 +978,30 @@ choose_enum_order (void)
       enum_order[next++] = c;
   address_end = next;
 
+  maybe_allows_none_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+       && !c->maybe_allows_reg && !c->maybe_allows_mem)
+      enum_order[next++] = c;
+  maybe_allows_none_end = next;
+
+  maybe_allows_reg_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+       && c->maybe_allows_reg && !c->maybe_allows_mem)
+      enum_order[next++] = c;
+  maybe_allows_reg_end = next;
+
+  maybe_allows_mem_start = next;
+  FOR_ALL_CONSTRAINTS (c)
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+       && !c->maybe_allows_reg && c->maybe_allows_mem)
+      enum_order[next++] = c;
+  maybe_allows_mem_end = next;
+
   FOR_ALL_CONSTRAINTS (c)
-    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address)
+    if (!c->is_register && !c->is_const_int && !c->is_memory && !c->is_address
+       && c->maybe_allows_reg && c->maybe_allows_mem)
       enum_order[next++] = c;
   gcc_assert (next == num_constraints);
 }
@@ -1229,6 +1289,41 @@ write_range_function (const char *name, unsigned int start, unsigned int end)
            "}\n\n", name);
 }
 
+/* Write a definition for insn_extra_constraint_allows_reg_mem function.  */
+static void
+write_allows_reg_mem_function (void)
+{
+  printf ("static inline void\n"
+         "insn_extra_constraint_allows_reg_mem (enum constraint_num c,\n"
+         "\t\t\t\t      bool *allows_reg, bool *allows_mem)\n"
+         "{\n");
+  if (maybe_allows_none_start != maybe_allows_none_end)
+    printf ("  if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n"
+           "    return;\n",
+           enum_order[maybe_allows_none_start]->c_name,
+           enum_order[maybe_allows_none_end - 1]->c_name);
+  if (maybe_allows_reg_start != maybe_allows_reg_end)
+    printf ("  if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n"
+           "    {\n"
+           "      *allows_reg = true;\n"
+           "      return;\n"
+           "    }\n",
+           enum_order[maybe_allows_reg_start]->c_name,
+           enum_order[maybe_allows_reg_end - 1]->c_name);
+  if (maybe_allows_mem_start != maybe_allows_mem_end)
+    printf ("  if (c >= CONSTRAINT_%s && c <= CONSTRAINT_%s)\n"
+           "    {\n"
+           "      *allows_mem = true;\n"
+           "      return;\n"
+           "    }\n",
+           enum_order[maybe_allows_mem_start]->c_name,
+           enum_order[maybe_allows_mem_end - 1]->c_name);
+  printf ("  (void) c;\n"
+         "  *allows_reg = true;\n"
+         "  *allows_mem = true;\n"
+         "}\n\n");
+}
+
 /* 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.
@@ -1326,6 +1421,7 @@ write_tm_preds_h (void)
                            memory_start, memory_end);
       write_range_function ("insn_extra_address_constraint",
                            address_start, address_end);
+      write_allows_reg_mem_function ();
 
       if (constraint_max_namelen > 1)
         {
index 45dc45fd049aed27d63ba8d47a00dd2858afafb3..6c62a129601ccb65d5f7cb289c197d5e653003d8 100644 (file)
@@ -342,13 +342,7 @@ parse_output_constraint (const char **constraint_p, int operand_num,
        else if (insn_extra_memory_constraint (cn))
          *allows_mem = true;
        else
-         {
-           /* Otherwise we can't assume anything about the nature of
-              the constraint except that it isn't purely registers.
-              Treat it like "g" and hope for the best.  */
-           *allows_reg = true;
-           *allows_mem = true;
-         }
+         insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
        break;
       }
 
@@ -465,13 +459,7 @@ parse_input_constraint (const char **constraint_p, int input_num,
        else if (insn_extra_memory_constraint (cn))
          *allows_mem = true;
        else
-         {
-           /* Otherwise we can't assume anything about the nature of
-              the constraint except that it isn't purely registers.
-              Treat it like "g" and hope for the best.  */
-           *allows_reg = true;
-           *allows_mem = true;
-         }
+         insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
        break;
       }
 
index c6bd2eda4b674866ab686318add553b1c3e48f3a..cec5fa10bfee43c015b39660ac10ffe5c812391d 100644 (file)
@@ -1,3 +1,8 @@
+2015-04-17  Jakub Jelinek  <jakub@redhat.com>
+
+       PR target/65689
+       * gcc.target/aarch64/c-output-template-4.c: New test.
+
 2015-04-17  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/65780
diff --git a/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c b/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c
new file mode 100644 (file)
index 0000000..c5a9391
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+void
+test (void)
+{
+    __asm__ ("@ %c0" : : "S" (&test + 4));
+}
+
+/* { dg-final { scan-assembler "@ test\\+4" } } */