aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2018-11-09 10:16:09 +0000
committerAlexandre Oliva <aoliva@gcc.gnu.org>2018-11-09 10:16:09 +0000
commitd4920f402af2591fa9864863f8c4ddcad1f9ebc1 (patch)
treefca3caf0766d3151c362068508b4da0f0763b702 /gcc
parentb759ea284782b95cf0196c8e813e3ab7e1233c47 (diff)
downloadgcc-d4920f402af2591fa9864863f8c4ddcad1f9ebc1.zip
gcc-d4920f402af2591fa9864863f8c4ddcad1f9ebc1.tar.gz
gcc-d4920f402af2591fa9864863f8c4ddcad1f9ebc1.tar.bz2
[PR86438] compare-elim: cope with set of in_b
When in_a resolves to a register set in the prev_clobber insn, we may use the SET_SRC for the compare instead. However, when in_b so resolves, we proceed to use the reg with its earlier value. When both resolve to the same register and prev_clobber is an insn that modifies the register, this arrangement may cause the compare to match (when it shouldn't) and the elimination of the compare to incorrectly succeed. (set (reg 1) (plus (reg 1) (const_int N))) (set (reg 2) (reg 1)) (set (reg flags) (compare (reg 1) (reg 2))) in_a: (reg 1) --> (plus (reg 1) (const_int N)) in_b: (reg 2) -> (reg 1) -/> oops (parallel [ (set (reg flags) (compare (plus (reg 1) (const_int N)) (reg 1))) ;; should be (plus...) (set (reg 1) (plus (reg 1) (const_int N)))]) (set (reg 2) (reg 1)) This patch arranges for in_b to also undergo SET_SRC substitution when appropriate, with a shortcut for when in_a and in_b are the same rtx. for gcc/ChangeLog 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. for gcc/testsuite/ChangeLog PR rtl-optimization/86438 * gcc.dg/torture/pr86438.c: New. From-SVN: r265957
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/compare-elim.c25
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr86438.c29
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;
+}