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; +} +