From 96eca8f423347be271fd084c48beb985837e0a02 Mon Sep 17 00:00:00 2001 From: segher Date: Tue, 13 Feb 2018 22:12:55 +0000 Subject: combine: Update links correctly for new I2 (PR84169) If there is a LOG_LINK between two insns, this means those two insns can be combined, as far as dataflow is concerned. There never should be a LOG_LINK between two unrelated insns. If there is one, combine will try to combine the insns without doing all the needed checks if the earlier destination is used before the later insn, etc. Unfortunately we do not update the LOG_LINKs correctly in some cases. This patch fixes at least some of those cases. PR rtl-optimization/84169 * combine.c (try_combine): New variable split_i2i3. Set it to true if we generated a parallel as new i3 and we split that to new i2 and i3 instructions. Handle split_i2i3 similar to swap_i2i3: scan the LOG_LINKs of i3 to see which of those need to link to i2 now. Link those to i2, not i1. Partially rewrite this scan code. gcc/testsuite/ PR rtl-optimization/84169 * gcc.c-torture/execute/pr84169.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@257644 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/combine.c | 57 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 26 deletions(-) (limited to 'gcc/combine.c') diff --git a/gcc/combine.c b/gcc/combine.c index a9929f2a3e2..c4d55eb85a4 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -2665,6 +2665,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, /* Notes that I1, I2 or I3 is a MULT operation. */ int have_mult = 0; int swap_i2i3 = 0; + int split_i2i3 = 0; int changed_i3_dest = 0; int maxreg; @@ -4091,6 +4092,9 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, } insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes); + + if (insn_code_number >= 0) + split_i2i3 = 1; } } @@ -4258,44 +4262,45 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (swap_i2i3) { - rtx_insn *insn; - struct insn_link *link; - rtx ni2dest; - /* I3 now uses what used to be its destination and which is now I2's destination. This requires us to do a few adjustments. */ PATTERN (i3) = newpat; adjust_for_new_dest (i3); + } - /* We need a LOG_LINK from I3 to I2. But we used to have one, - so we still will. + if (swap_i2i3 || split_i2i3) + { + /* We might need a LOG_LINK from I3 to I2. But then we used to + have one, so we still will. However, some later insn might be using I2's dest and have - a LOG_LINK pointing at I3. We must remove this link. - The simplest way to remove the link is to point it at I1, - which we know will be a NOTE. */ + a LOG_LINK pointing at I3. We should change it to point at + I2 instead. */ /* newi2pat is usually a SET here; however, recog_for_combine might have added some clobbers. */ - if (GET_CODE (newi2pat) == PARALLEL) - ni2dest = SET_DEST (XVECEXP (newi2pat, 0, 0)); - else - ni2dest = SET_DEST (newi2pat); - - for (insn = NEXT_INSN (i3); - insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun) - || insn != BB_HEAD (this_basic_block->next_bb)); + rtx x = newi2pat; + if (GET_CODE (x) == PARALLEL) + x = XVECEXP (newi2pat, 0, 0); + + unsigned int regno = REGNO (SET_DEST (x)); + + bool done = false; + for (rtx_insn *insn = NEXT_INSN (i3); + !done + && insn + && NONDEBUG_INSN_P (insn) + && BLOCK_FOR_INSN (insn) == this_basic_block; insn = NEXT_INSN (insn)) { - if (NONDEBUG_INSN_P (insn) - && reg_referenced_p (ni2dest, PATTERN (insn))) - { - FOR_EACH_LOG_LINK (link, insn) - if (link->insn == i3) - link->insn = i1; - - break; - } + struct insn_link *link; + FOR_EACH_LOG_LINK (link, insn) + if (link->insn == i3 && link->regno == regno) + { + link->insn = i2; + done = true; + break; + } } } -- cgit v1.2.1 From ad0959559ad5df2dc8f6dbebd5a39e529e9785e9 Mon Sep 17 00:00:00 2001 From: segher Date: Fri, 16 Feb 2018 14:03:17 +0000 Subject: combine: Fix problem with RTL checking As Jakub found, after my recent combine patch at least on x86 problems show up with RTL checking enabled. This is because the I2 generated by a successful instruction combination can write not only a register but it can also write a paradoxical subreg of one. This fixes it. * combine.c (try_combine): When adjusting LOG_LINKS for the destination that moved to I2, also allow destinations that are a paradoxical subreg (instead of a normal reg). git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@257736 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/combine.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'gcc/combine.c') diff --git a/gcc/combine.c b/gcc/combine.c index c4d55eb85a4..6b761c609ae 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -4283,7 +4283,12 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0, if (GET_CODE (x) == PARALLEL) x = XVECEXP (newi2pat, 0, 0); - unsigned int regno = REGNO (SET_DEST (x)); + /* It can only be a SET of a REG or of a paradoxical SUBREG of a REG. */ + x = SET_DEST (x); + if (paradoxical_subreg_p (x)) + x = SUBREG_REG (x); + + unsigned int regno = REGNO (x); bool done = false; for (rtx_insn *insn = NEXT_INSN (i3); -- cgit v1.2.1