@@ -1454,15 +1454,21 @@ combine_instructions (rtx_insn *f, unsig
&& ! 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, unsig
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;
}
}
@@ -3915,9 +3915,9 @@ indicates that that register will be equ
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
@@ -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;
+}