diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/compare-elim.c | 25 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr86438.c | 29 |
4 files changed, 53 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 21d9ae7..46ab4e9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,9 @@ 2018-11-09 Alexandre Oliva <aoliva@redhat.com> + PR rtl-optimization/86438 + * compare-elim.c (try_eliminate_compare): Use SET_SRC instead + of in_b for the compare if in_b is SET_DEST. + PR target/87793 * config/i386/i386.c (ix86_const_not_ok_for_debug_p): Reject non-toplevel UNSPEC. diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c index 50bbaa8..8afbe76 100644 --- a/gcc/compare-elim.c +++ b/gcc/compare-elim.c @@ -734,7 +734,7 @@ try_merge_compare (struct comparison *cmp) 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; @@ -786,7 +786,7 @@ try_eliminate_compare (struct comparison *cmp) 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) @@ -800,7 +800,7 @@ try_eliminate_compare (struct comparison *cmp) && (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) @@ -811,7 +811,7 @@ try_eliminate_compare (struct comparison *cmp) && 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; @@ -819,17 +819,26 @@ try_eliminate_compare (struct comparison *cmp) /* 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: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9a7dfc2..6434be0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2018-11-09 Alexandre Oliva <aoliva@redhat.com> + PR rtl-optimization/86438 + * gcc.dg/torture/pr86438.c: New. + PR target/87793 * gcc.dg/pr87793.c: New. diff --git a/gcc/testsuite/gcc.dg/torture/pr86438.c b/gcc/testsuite/gcc.dg/torture/pr86438.c new file mode 100644 index 0000000..3e95515 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr86438.c @@ -0,0 +1,29 @@ +/* { 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; +} |