re PR rtl-optimization/87600 (Fix for PRs 86939 and 87479 causes build issues for...
authorPeter Bergner <bergner@linux.ibm.com>
Thu, 8 Nov 2018 22:39:45 +0000 (22:39 +0000)
committerPeter Bergner <bergner@gcc.gnu.org>
Thu, 8 Nov 2018 22:39:45 +0000 (16:39 -0600)
gcc/
PR rtl-optimization/87600
* cfgexpand.c (expand_asm_stmt): Catch illegal asm constraint usage.
* lra-constraints.c (process_alt_operands): Skip illegal hard
register usage.  Prefer reloading non hard register operands.

gcc/testsuite/
PR rtl-optimization/87600
* gcc.dg/pr87600.h: New file.
* gcc.dg/pr87600-1.c: New test.
* gcc.dg/pr87600-2.c: Likewise.

From-SVN: r265942

gcc/ChangeLog
gcc/cfgexpand.c
gcc/lra-constraints.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr87600-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr87600-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr87600.h [new file with mode: 0644]

index a7a6ddb..8578874 100644 (file)
@@ -1,3 +1,16 @@
+2018-11-08  Peter Bergner  <bergner@linux.ibm.com>
+
+       PR rtl-optimization/87600
+       * cfgexpand.c (expand_asm_stmt): Catch illegal asm constraint usage.
+       * lra-constraints.c (process_alt_operands): Skip illegal hard
+       register usage.  Prefer reloading non hard register operands.
+
+gcc/testsuite/
+       PR rtl-optimization/87600
+       * gcc.dg/pr87600.h: New file.
+       * gcc.dg/pr87600-1.c: New test.
+       * gcc.dg/pr87600-2.c: Likewise.
+
 2018-11-08  Sandra Loosemore  <sandra@codesourcery.com>
 
        PR other/36572
@@ -12,7 +25,7 @@
        * common.opt (-fuse-ld=lld): New option.
        * doc/invoke.texi (-fuse-ld=lld): Document.
        * opts.c (common_handle_option): Handle OPT_fuse_ld_lld.
-       
+
 2018-11-08  Paul Koning  <ni1d@arrl.net>
 
        * config/pdp11/constraints.md: Add "Z" series constraints for use
index 672fc57..8fa392f 100644 (file)
@@ -3010,6 +3010,55 @@ expand_asm_stmt (gasm *stmt)
                                    &allows_mem, &allows_reg, &is_inout))
        return;
 
+      /* If the output is a hard register, verify it doesn't conflict with
+        any other operand's possible hard register use.  */
+      if (DECL_P (val)
+         && REG_P (DECL_RTL (val))
+         && HARD_REGISTER_P (DECL_RTL (val)))
+       {
+         unsigned j, output_hregno = REGNO (DECL_RTL (val));
+         bool early_clobber_p = strchr (constraints[i], '&') != NULL;
+         unsigned long match;
+
+         /* Verify the other outputs do not use the same hard register.  */
+         for (j = i + 1; j < noutputs; ++j)
+           if (DECL_P (output_tvec[j])
+               && REG_P (DECL_RTL (output_tvec[j]))
+               && HARD_REGISTER_P (DECL_RTL (output_tvec[j]))
+               && output_hregno == REGNO (DECL_RTL (output_tvec[j])))
+             error ("invalid hard register usage between output operands");
+
+         /* Verify matching constraint operands use the same hard register
+            and that the non-matching constraint operands do not use the same
+            hard register if the output is an early clobber operand.  */
+         for (j = 0; j < ninputs; ++j)
+           if (DECL_P (input_tvec[j])
+               && REG_P (DECL_RTL (input_tvec[j]))
+               && HARD_REGISTER_P (DECL_RTL (input_tvec[j])))
+             {
+               unsigned input_hregno = REGNO (DECL_RTL (input_tvec[j]));
+               switch (*constraints[j + noutputs])
+                 {
+                 case '0':  case '1':  case '2':  case '3':  case '4':
+                 case '5':  case '6':  case '7':  case '8':  case '9':
+                   match = strtoul (constraints[j + noutputs], NULL, 10);
+                   break;
+                 default:
+                   match = ULONG_MAX;
+                   break;
+                 }
+               if (i == match
+                   && output_hregno != input_hregno)
+                 error ("invalid hard register usage between output operand "
+                        "and matching constraint operand");
+               else if (early_clobber_p
+                        && i != match
+                        && output_hregno == input_hregno)
+                 error ("invalid hard register usage between earlyclobber "
+                        "operand and input operand");
+             }
+       }
+
       if (! allows_reg
          && (allows_mem
              || is_inout
index ab61989..88546d2 100644 (file)
@@ -2146,9 +2146,32 @@ process_alt_operands (int only_alternative)
                      }
                    else
                      {
-                       /* Operands don't match.  Both operands must
-                          allow a reload register, otherwise we
-                          cannot make them match.  */
+                       /* Operands don't match.  If the operands are
+                          different user defined explicit hard registers,
+                          then we cannot make them match.  */
+                       if ((REG_P (*curr_id->operand_loc[nop])
+                            || SUBREG_P (*curr_id->operand_loc[nop]))
+                           && (REG_P (*curr_id->operand_loc[m])
+                               || SUBREG_P (*curr_id->operand_loc[m])))
+                         {
+                           rtx nop_reg = *curr_id->operand_loc[nop];
+                           if (SUBREG_P (nop_reg))
+                             nop_reg = SUBREG_REG (nop_reg);
+                           rtx m_reg = *curr_id->operand_loc[m];
+                           if (SUBREG_P (m_reg))
+                             m_reg = SUBREG_REG (m_reg);
+
+                           if (REG_P (nop_reg)
+                               && HARD_REGISTER_P (nop_reg)
+                               && REG_USERVAR_P (nop_reg)
+                               && REG_P (m_reg)
+                               && HARD_REGISTER_P (m_reg)
+                               && REG_USERVAR_P (m_reg))
+                             break;
+                         }
+
+                       /* Both operands must allow a reload register,
+                          otherwise we cannot make them match.  */
                        if (curr_alt[m] == NO_REGS)
                          break;
                        /* Retroactively mark the operand we had to
@@ -2910,18 +2933,31 @@ process_alt_operands (int only_alternative)
                if (first_conflict_j < 0)
                  first_conflict_j = j;
                last_conflict_j = j;
+               /* Both the earlyclobber operand and conflicting operand
+                  cannot both be user defined hard registers.  */
+               if (HARD_REGISTER_P (operand_reg[i])
+                   && REG_USERVAR_P (operand_reg[i])
+                   && operand_reg[j] != NULL_RTX
+                   && HARD_REGISTER_P (operand_reg[j])
+                   && REG_USERVAR_P (operand_reg[j]))
+                 fatal_insn ("unable to generate reloads for "
+                             "impossible constraints:", curr_insn);
              }
          if (last_conflict_j < 0)
            continue;
-         /* If earlyclobber operand conflicts with another
-            non-matching operand which is actually the same register
-            as the earlyclobber operand, it is better to reload the
-            another operand as an operand matching the earlyclobber
-            operand can be also the same.  */
-         if (first_conflict_j == last_conflict_j
-             && operand_reg[last_conflict_j] != NULL_RTX
-             && ! curr_alt_match_win[last_conflict_j]
-             && REGNO (operand_reg[i]) == REGNO (operand_reg[last_conflict_j]))
+
+         /* If an earlyclobber operand conflicts with another non-matching
+            operand (ie, they have been assigned the same hard register),
+            then it is better to reload the other operand, as there may
+            exist yet another operand with a matching constraint associated
+            with the earlyclobber operand.  However, if one of the operands
+            is an explicit use of a hard register, then we must reload the
+            other non-hard register operand.  */
+         if (HARD_REGISTER_P (operand_reg[i])
+             || (first_conflict_j == last_conflict_j
+                 && operand_reg[last_conflict_j] != NULL_RTX
+                 && !curr_alt_match_win[last_conflict_j]
+                 && !HARD_REGISTER_P (operand_reg[last_conflict_j])))
            {
              curr_alt_win[last_conflict_j] = false;
              curr_alt_dont_inherit_ops[curr_alt_dont_inherit_ops_num++]
index c227dc9..4769e45 100644 (file)
@@ -1,3 +1,10 @@
+2018-11-08  Peter Bergner  <bergner@linux.ibm.com>
+
+       PR rtl-optimization/87600
+       * gcc.dg/pr87600.h: New file.
+       * gcc.dg/pr87600-1.c: New test.
+       * gcc.dg/pr87600-2.c: Likewise.
+
 2018-11-08  Jakub Jelinek  <jakub@redhat.com>
 
        * c-c++-common/gomp/atomic-17.c: New test.
diff --git a/gcc/testsuite/gcc.dg/pr87600-1.c b/gcc/testsuite/gcc.dg/pr87600-1.c
new file mode 100644 (file)
index 0000000..3517957
--- /dev/null
@@ -0,0 +1,52 @@
+/* PR rtl-optimization/87600  */
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+#include "pr87600.h"
+
+/* The following are all valid uses of local register variables.  */
+
+long
+test0 (long arg)
+{
+  register long var asm (REG1);
+  asm ("blah %0 %1" : "+&r" (var) : "r" (arg));
+  return var;
+}
+
+long
+test1 (long arg0, long arg1)
+{
+  register long var asm (REG1);
+  asm ("blah %0, %1, %2" : "=&r" (var) : "r" (arg0), "0" (arg1));
+  return var + arg1;
+}
+
+long
+test2 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG1);
+  asm ("blah %0 %1" : "=&r" (var1) : "0" (var2));
+  return var1;
+}
+
+long
+test3 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG2);
+  long var3;
+  asm ("blah %0 %1" : "=&r" (var1), "=r" (var3) : "1" (var2));
+  return var1 + var3;
+}
+
+long
+test4 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG2);
+  register long var3 asm (REG2);
+  asm ("blah %0 %1" : "=&r" (var1), "=r" (var2) : "1" (var3));
+  return var1;
+}
diff --git a/gcc/testsuite/gcc.dg/pr87600-2.c b/gcc/testsuite/gcc.dg/pr87600-2.c
new file mode 100644 (file)
index 0000000..e8a9f19
--- /dev/null
@@ -0,0 +1,44 @@
+/* PR rtl-optimization/87600  */
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+#include "pr87600.h"
+
+/* The following are all invalid uses of local register variables.  */
+
+long
+test0 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG1);
+  asm ("blah %0 %1" : "=r" (var1), "=r" (var2)); /* { dg-error "invalid hard register usage between output operands" } */
+  return var1;
+}
+
+long
+test1 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG2);
+  asm ("blah %0 %1" : "=r" (var1) : "0" (var2)); /* { dg-error "invalid hard register usage between output operand and matching constraint operand" } */
+  return var1;
+}
+
+long
+test2 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG1);
+  asm ("blah %0 %1" : "=&r" (var1) : "r" (var2)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+  return var1;
+}
+
+long
+test3 (void)
+{
+  register long var1 asm (REG1);
+  register long var2 asm (REG1);
+  long var3;
+  asm ("blah %0 %1" : "=&r" (var1), "=r" (var3) : "1" (var2)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+  return var1 + var3;
+}
diff --git a/gcc/testsuite/gcc.dg/pr87600.h b/gcc/testsuite/gcc.dg/pr87600.h
new file mode 100644 (file)
index 0000000..5ebb928
--- /dev/null
@@ -0,0 +1,19 @@
+#if defined (__aarch64__)
+# define REG1 "x0"
+# define REG2 "x1"
+#elif defined (__arm__)
+# define REG1 "r0"
+# define REG2 "r1"
+#elif defined (__i386__)
+# define REG1 "%eax"
+# define REG2 "%edx"
+#elif defined (__powerpc__)
+# define REG1 "r3"
+# define REG2 "r4"
+#elif defined (__s390__)
+# define REG1 "0"
+# define REG2 "1"
+#elif defined (__x86_64__)
+# define REG1 "rax"
+# define REG2 "rdx"
+#endif