diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 70e5fd61f3b..17f9b2b8217 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2016-01-26 Jakub Jelinek + + PR target/69442 + * combine.c (combine_instructions): For REG_EQUAL note with + SET_DEST being ZERO_EXTRACT, also temporarily set SET_DEST + to the underlying register. + * doc/rtl.texi (REG_EQUAL): Document the behavior of + REG_EQUAL/REG_EQUIV notes if SET_DEST is ZERO_EXTRACT. + 2016-01-26 Roger Ferrer Ibáñez PR target/67896 diff --git a/gcc/combine.c b/gcc/combine.c index 2f913dd8ea9..858552ddc3f 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -1454,15 +1454,21 @@ combine_instructions (rtx_insn *f, unsigned int nregs) && ! unmentioned_reg_p (note, SET_SRC (set)) && (GET_MODE (note) == VOIDmode ? SCALAR_INT_MODE_P (GET_MODE (SET_DEST (set))) - : GET_MODE (SET_DEST (set)) == GET_MODE (note))) + : (GET_MODE (SET_DEST (set)) == GET_MODE (note) + && (GET_CODE (SET_DEST (set)) != ZERO_EXTRACT + || (GET_MODE (XEXP (SET_DEST (set), 0)) + == GET_MODE (note)))))) { /* Temporarily replace the set's source with the contents of the REG_EQUAL note. The insn will be deleted or recognized by try_combine. */ - rtx orig = SET_SRC (set); + rtx orig_src = SET_SRC (set); + rtx orig_dest = SET_DEST (set); + if (GET_CODE (SET_DEST (set)) == ZERO_EXTRACT) + SET_DEST (set) = XEXP (SET_DEST (set), 0); SET_SRC (set) = note; i2mod = temp; - i2mod_old_rhs = copy_rtx (orig); + i2mod_old_rhs = copy_rtx (orig_src); i2mod_new_rhs = copy_rtx (note); next = try_combine (insn, i2mod, NULL, NULL, &new_direct_jump_p, @@ -1473,7 +1479,8 @@ combine_instructions (rtx_insn *f, unsigned int nregs) statistics_counter_event (cfun, "insn-with-note combine", 1); goto retry; } - SET_SRC (set) = orig; + SET_SRC (set) = orig_src; + SET_DEST (set) = orig_dest; } } diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index e44ef53d851..1b3f47e3573 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -3915,9 +3915,9 @@ indicates that that register will be equal to @var{op} at run time; the scope of this equivalence differs between the two types of notes. The value which the insn explicitly copies into the register may look different from @var{op}, but they will be equal at run time. If the -output of the single @code{set} is a @code{strict_low_part} expression, -the note refers to the register that is contained in @code{SUBREG_REG} -of the @code{subreg} expression. +output of the single @code{set} is a @code{strict_low_part} or +@code{zero_extract} expression, the note refers to the register that +is contained in its first operand. For @code{REG_EQUIV}, the register is equivalent to @var{op} throughout the entire function, and could validly be replaced in all its diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ae150baa578..67bc4e4cf57 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-01-26 Jakub Jelinek + + PR target/69442 + * gcc.dg/pr69442.c: New test. + 2016-01-26 Roger Ferrer Ibáñez PR target/67896 diff --git a/gcc/testsuite/gcc.dg/pr69442.c b/gcc/testsuite/gcc.dg/pr69442.c new file mode 100644 index 00000000000..ee75f92951a --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr69442.c @@ -0,0 +1,23 @@ +/* PR target/69442 */ +/* { dg-do run } */ +/* { dg-options "-Og" } */ + +unsigned long long __attribute__ ((noinline, noclone)) +foo (unsigned int x, unsigned long long y) +{ + x |= 0xffff; + y -= 0xffULL; + y %= 0xffff0000ffffffe7ULL; + return x + y; +} + +int +main () +{ + if (sizeof (unsigned long long) * __CHAR_BIT__ != 64) + return 0; + + if (foo (0, 0) != 0xffff0000ff19ULL) + __builtin_abort (); + return 0; +}