From 4a17943d36f2890fabc5e2f05eb2f8aca4b319c2 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Fri, 17 Mar 2017 09:10:13 -0600 Subject: [PATCH] re PR rtl-optimization/79910 (wrong code with -O -fweb) PR rtl-optimization/79910 * combine.c (record_used_regs): New static function. (try_combine): Handle situations where there is an additional instruction between I2 and I3 which needs to have a LOG_LINK updated. PR rtl-optimization/79910 * gcc.dg/torture/pr79910.c: New test. From-SVN: r246226 --- gcc/ChangeLog | 8 ++ gcc/combine.c | 138 +++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/torture/pr79910.c | 29 ++++++ 4 files changed, 180 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/torture/pr79910.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 71bebcf9fb3..f6caadb967f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2017-03-17 Bernd Schmidt + + PR rtl-optimization/79910 + * combine.c (record_used_regs): New static function. + (try_combine): Handle situations where there is an additional + instruction between I2 and I3 which needs to have a LOG_LINK + updated. + 2017-03-17 Jeff Law PR tree-optimization/71437 diff --git a/gcc/combine.c b/gcc/combine.c index 66215a607bd..ff0df80a801 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -2559,6 +2559,57 @@ can_split_parallel_of_n_reg_sets (rtx_insn *insn, int n) return true; } +/* Set up a set of registers used in an insn. Called through note_uses, + arguments as described for that function. */ + +static void +record_used_regs (rtx *xptr, void *data) +{ + bitmap set = (bitmap)data; + int i, j; + enum rtx_code code; + const char *fmt; + rtx x = *xptr; + + /* repeat is used to turn tail-recursion into iteration since GCC + can't do it when there's no return value. */ + repeat: + if (x == 0) + return; + + code = GET_CODE (x); + if (REG_P (x)) + { + unsigned regno = REGNO (x); + unsigned end_regno = END_REGNO (x); + while (regno < end_regno) + bitmap_set_bit (set, regno++); + return; + } + + /* Recursively scan the operands of this expression. */ + + for (i = GET_RTX_LENGTH (code) - 1, fmt = GET_RTX_FORMAT (code); i >= 0; i--) + { + if (fmt[i] == 'e') + { + /* If we are about to do the last recursive call + needed at this level, change it into iteration. + This function is called enough to be worth it. */ + if (i == 0) + { + x = XEXP (x, 0); + goto repeat; + } + + record_used_regs (&XEXP (x, i), data); + } + else if (fmt[i] == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + record_used_regs (&XVECEXP (x, i, j), data); + } +} + /* Try to combine the insns I0, I1 and I2 into I3. Here I0, I1 and I2 appear earlier than I3. I0 and I1 can be zero; then we combine just I2 into I3, or I1 and I2 into @@ -2742,6 +2793,27 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, added_links_insn = 0; + /* For combinations that may result in two insns, we have to gather + some extra information about registers used, so that we can + update all relevant LOG_LINKS later. */ + auto_bitmap i2_regset, i3_regset, links_regset; + if (i1) + { + note_uses (&PATTERN (i2), record_used_regs, (bitmap)i2_regset); + note_uses (&PATTERN (i3), record_used_regs, (bitmap)i3_regset); + insn_link *ll; + FOR_EACH_LOG_LINK (ll, i3) + bitmap_set_bit (links_regset, ll->regno); + FOR_EACH_LOG_LINK (ll, i2) + bitmap_set_bit (links_regset, ll->regno); + if (i1) + FOR_EACH_LOG_LINK (ll, i1) + bitmap_set_bit (links_regset, ll->regno); + if (i0) + FOR_EACH_LOG_LINK (ll, i0) + bitmap_set_bit (links_regset, ll->regno); + } + /* First check for one important special case that the code below will not handle. Namely, the case where I1 is zero, I2 is a PARALLEL and I3 is a SET whose SET_SRC is a SET_DEST in I2. In that case, @@ -4051,6 +4123,33 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, return 0; } + auto_bitmap new_regs_in_i2; + if (newi2pat) + { + /* We need to discover situations where we introduce a use of a + register into I2, where none of the existing LOG_LINKS contain + a reference to it. This can happen if previously I3 referenced + the reg, and there is an additional use between I2 and I3. We + must remove the LOG_LINKS entry from that additional use and + distribute it along with our own ones. */ + note_uses (&newi2pat, record_used_regs, (bitmap)new_regs_in_i2); + bitmap_and_compl_into (new_regs_in_i2, i2_regset); + bitmap_and_compl_into (new_regs_in_i2, links_regset); + + /* Here, we first look for situations where a hard register use + moved, and just give up. This should happen approximately + never, and it's not worth it to deal with possibilities like + multi-word registers. Later, when fixing up LOG_LINKS, we + deal with the case where a pseudo use moved. */ + if (!bitmap_empty_p (new_regs_in_i2) + && prev_nonnote_insn (i3) != i2 + && bitmap_first_set_bit (new_regs_in_i2) < FIRST_PSEUDO_REGISTER) + { + undo_all (); + return 0; + } + } + if (MAY_HAVE_DEBUG_INSNS) { struct undo *undo; @@ -4493,6 +4592,45 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, NULL_RTX, NULL_RTX, NULL_RTX); } + if (newi2pat) + { + bitmap_iterator iter; + unsigned int i; + + /* See comments above where we calculate the bitmap. */ + EXECUTE_IF_SET_IN_BITMAP ((bitmap)new_regs_in_i2, + LAST_VIRTUAL_REGISTER, i, iter) + { + rtx reg = regno_reg_rtx[i]; + rtx_insn *other; + for (other = NEXT_INSN (i2); other != i3; other = NEXT_INSN (other)) + if (NONDEBUG_INSN_P (other) + && (reg_overlap_mentioned_p (reg, PATTERN (other)) + || (CALL_P (other) && find_reg_fusage (other, USE, reg)))) + { + if (dump_file) + fprintf (dump_file, + "found extra use of reg %d at insn %d\n", i, + INSN_UID (other)); + insn_link **plink; + for (plink = &LOG_LINKS (other); + *plink; + plink = &(*plink)->next) + { + insn_link *link = *plink; + if (link->regno == i) + { + *plink = link->next; + link->next = i3links; + i3links = link; + break; + } + } + break; + } + } + } + distribute_links (i3links); distribute_links (i2links); distribute_links (i1links); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ab4a49d5ffa..4162ca23eed 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-03-17 Bernd Schmidt + + PR rtl-optimization/79910 + * gcc.dg/torture/pr79910.c: New test. + 2017-03-17 Jeff Law PR tree-optimization/71437 diff --git a/gcc/testsuite/gcc.dg/torture/pr79910.c b/gcc/testsuite/gcc.dg/torture/pr79910.c new file mode 100644 index 00000000000..5fe80aee144 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr79910.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fweb" } */ + +typedef unsigned char u8; +typedef unsigned int u32; +typedef unsigned long long u64; +int a; + +static __attribute__ ((noinline, noclone)) u64 +foo (u8 p1, u32 p2) +{ + u64 b = a <= 0; + p2 = 4; + b >>= a == 0; + p1 %= 0xfffffffff; + p2 >>= b & 31; + p1 += b; + p2 <<= 31; + return p1 + p2 + b; +} + +int +main (void) +{ + u64 x = foo (0, 1); + if (x != 0) + __builtin_abort (); + return 0; +} -- 2.30.2