diff options
-rw-r--r-- | gcc/combine.c | 15 | ||||
-rw-r--r-- | gcc/doc/rtl.texi | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr69442.c | 23 |
3 files changed, 37 insertions, 7 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index f117015bb72..c00d82b8ef5 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -1494,15 +1494,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, @@ -1513,7 +1519,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 141c957c99f..1c1fc9dc9a2 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/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; +} |