As Andrey outlined in the PR, selective-scheduling was missing a check & handling of hard registers in modes that span more than one hard reg. This caused an incorrect register selection during renaming.

I verified removing the printf call from the test would not compromise the test. Then I did a normal x86 bootstrap & regression test with the patch. Of course that's essentially useless, so I also did another bootstrap and regression test with -fselective-scheduling in BOOT_CFLAGS with and without this patch. In both cases there were no regressions.

I'm installing Andrey's patch on the trunk. I'm not sure this is worth addressing in gcc-5.

Jeff
commit 7965fd4e4fdd06addbca2f4a92657df6cadbd002
Author: law <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Sat Mar 12 17:12:29 2016 +0000

        PR rtl-optimization/69307
        * sel-sched.c (choose_best_pseudo_reg): Properly check for hard
        registers in modes that span more than one register.
    
        PR rtl-optimization/69307
        * gcc.dg/pr69307.c: New test.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@234163 
138bc75d-0d04-0410-961f-82ee72b054a4

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7d73d32..6c41cf0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2016-03-12  Andrey Belevantsev  <a...@ispras.ru>
+
+       PR rtl-optimization/69307
+       * sel-sched.c (choose_best_pseudo_reg): Properly check for hard
+       registers in modes that span more than one register.
+
 2016-03-12  Vladimir Makarov  <vmaka...@redhat.com>
 
        PR target/69614
diff --git a/gcc/sel-sched.c b/gcc/sel-sched.c
index bd32ab5..09cf028 100644
--- a/gcc/sel-sched.c
+++ b/gcc/sel-sched.c
@@ -1457,31 +1457,44 @@ choose_best_pseudo_reg (regset used_regs,
         gcc_assert (mode == GET_MODE (dest));
       orig_regno = REGNO (dest);
 
-      if (!REGNO_REG_SET_P (used_regs, orig_regno))
-        {
-          if (orig_regno < FIRST_PSEUDO_REGISTER)
-            {
-              gcc_assert (df_regs_ever_live_p (orig_regno));
+      /* Check that nothing in used_regs intersects with orig_regno.  When
+        we have a hard reg here, still loop over hard_regno_nregs.  */
+      if (HARD_REGISTER_NUM_P (orig_regno))
+       {
+         int j, n;
+         for (j = 0, n = hard_regno_nregs[orig_regno][mode]; j < n; j++)
+           if (REGNO_REG_SET_P (used_regs, orig_regno + j))
+             break;
+         if (j < n)
+           continue;
+       }
+      else
+       {
+         if (REGNO_REG_SET_P (used_regs, orig_regno))
+           continue;
+       }
+      if (HARD_REGISTER_NUM_P (orig_regno))
+       {
+         gcc_assert (df_regs_ever_live_p (orig_regno));
 
-              /* For hard registers, we have to check hardware imposed
-                 limitations (frame/stack registers, calls crossed).  */
-              if (!TEST_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs,
-                                      orig_regno))
-               {
-                 /* Don't let register cross a call if it doesn't already
-                    cross one.  This condition is written in accordance with
-                    that in sched-deps.c sched_analyze_reg().  */
-                 if (!reg_rename_p->crosses_call
-                     || REG_N_CALLS_CROSSED (orig_regno) > 0)
-                   return gen_rtx_REG (mode, orig_regno);
-               }
+         /* For hard registers, we have to check hardware imposed
+            limitations (frame/stack registers, calls crossed).  */
+         if (!TEST_HARD_REG_BIT (reg_rename_p->unavailable_hard_regs,
+                                 orig_regno))
+           {
+             /* Don't let register cross a call if it doesn't already
+                cross one.  This condition is written in accordance with
+                that in sched-deps.c sched_analyze_reg().  */
+             if (!reg_rename_p->crosses_call
+                 || REG_N_CALLS_CROSSED (orig_regno) > 0)
+               return gen_rtx_REG (mode, orig_regno);
+           }
 
-              bad_hard_regs = true;
-            }
-          else
-            return dest;
-        }
-     }
+         bad_hard_regs = true;
+       }
+      else
+       return dest;
+    }
 
   *is_orig_reg_p_ptr = false;
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4ef53c4..1334712 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-03-12  Andrey Belevantsev  <a...@ispras.ru>
+
+       PR rtl-optimization/69307
+       * gcc.dg/pr69307.c: New test.
+
 2016-03-12  Vladimir Makarov  <vmaka...@redhat.com>
 
        PR target/69614
diff --git a/gcc/testsuite/gcc.dg/pr69307.c b/gcc/testsuite/gcc.dg/pr69307.c
new file mode 100644
index 0000000..d9d343e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr69307.c
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fselective-scheduling2" } */
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long int uint64_t;
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+u64 __attribute__((noinline, noclone))
+foo(u8 u8_0, u16 u16_0, u32 u32_0, u64 u64_0, u8 u8_1, u16 u16_1, u32 u32_1, 
u64 u64_1, u8 u8_2, u16 u16_2, u32 u32_2, u64 u64_2, u8 u8_3, u16 u16_3, u32 
u32_3, u64 u64_3)
+{
+ u8 *p8_2 = &u8_2;
+ u16 *p16_2 = &u16_2;
+ u8 *p8_3 = &u8_3;
+ u64 *p64_3 = &u64_3;
+ p8_2 = &u8_3;
+ *p8_3 -= *p64_3;
+ *p8_2 = (u64)*p8_2 % ((u64)*p8_2 | 3);
+ u8_2 = (u64)u8_2 / ((u64)*p16_2 | 1);
+ u16_0 = (u64)u16_0 % ((u64)*p8_2 | 3);
+ return u8_0 + u16_0 + u32_0 + u64_0 + u8_1 + u16_1 + u32_1 + u64_1 + u8_2 + 
u16_2 + u32_2 + u64_2 + u8_3 + u16_3 + u32_3 + u64_3;
+}
+int main()
+{
+ u64 x = 0;
+ x += foo(3llu, 6llu, 15llu, 28llu, 5llu, 11llu, 20llu, 44llu, 7llu, 10llu, 
20llu, 55llu, 0llu, 9llu, 17llu, 48llu);
+ if (x != 0x1f3)
+        __builtin_abort();
+ return 0;
+}
+

Reply via email to