static bool
try_eliminate_compare (struct comparison *cmp)
{
- rtx flags, in_a, in_b, cmp_src;
+ rtx flags, in_a, in_b, cmp_a, cmp_b;
if (try_merge_compare (cmp))
return true;
rtx x = XVECEXP (PATTERN (insn), 0, 0);
if (rtx_equal_p (SET_DEST (x), in_a))
- cmp_src = SET_SRC (x);
+ cmp_a = SET_SRC (x);
/* Also check operations with implicit extensions, e.g.:
[(set (reg:DI)
&& (GET_CODE (SET_SRC (x)) == ZERO_EXTEND
|| GET_CODE (SET_SRC (x)) == SIGN_EXTEND)
&& GET_MODE (XEXP (SET_SRC (x), 0)) == GET_MODE (in_a))
- cmp_src = XEXP (SET_SRC (x), 0);
+ cmp_a = XEXP (SET_SRC (x), 0);
/* Also check fully redundant comparisons, e.g.:
[(set (reg:SI)
&& GET_CODE (SET_SRC (x)) == MINUS
&& rtx_equal_p (XEXP (SET_SRC (x), 0), in_a)
&& rtx_equal_p (XEXP (SET_SRC (x), 1), in_b))
- cmp_src = in_a;
+ cmp_a = in_a;
else
return false;
/* If the source uses addressing modes with side effects, we can't
do the merge because we'd end up with a PARALLEL that has two
instances of that side effect in it. */
- if (side_effects_p (cmp_src))
+ if (side_effects_p (cmp_a))
+ return false;
+
+ if (in_a == in_b)
+ cmp_b = cmp_a;
+ else if (rtx_equal_p (SET_DEST (x), in_b))
+ cmp_b = SET_SRC (x);
+ else
+ cmp_b = in_b;
+ if (side_effects_p (cmp_b))
return false;
/* Determine if we ought to use a different CC_MODE here. */
- flags = maybe_select_cc_mode (cmp, cmp_src, in_b);
+ flags = maybe_select_cc_mode (cmp, cmp_a, cmp_b);
if (flags == NULL)
flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
/* Generate a new comparison for installation in the setter. */
- rtx y = copy_rtx (cmp_src);
- y = gen_rtx_COMPARE (GET_MODE (flags), y, in_b);
+ rtx y = copy_rtx (cmp_a);
+ y = gen_rtx_COMPARE (GET_MODE (flags), y, copy_rtx (cmp_b));
y = gen_rtx_SET (flags, y);
/* Canonicalize instruction to:
--- /dev/null
+/* { dg-do run } */
+
+typedef unsigned int u32;
+#if __SIZEOF_INT128__
+typedef unsigned long long u64;
+typedef unsigned __int128 u128;
+#else
+typedef unsigned long u64;
+typedef unsigned long long u128;
+#endif
+
+u128 g;
+
+static __attribute__ ((noinline, noclone))
+void check (u64 a, u64 b)
+{
+ if (a != 0 || b != 4)
+ __builtin_abort ();
+}
+
+int
+main (void)
+{
+ u64 d = (g ? 5 : 4);
+ u32 f = __builtin_sub_overflow_p (d, (u128) d, (u64) 0);
+ u128 x = g + f + d;
+ check (x >> (sizeof (u64) * __CHAR_BIT__), x);
+ return 0;
+}