On Tue, Mar 21, 2017 at 06:53:34PM +0100, Jakub Jelinek wrote: > On Tue, Mar 21, 2017 at 08:41:43AM +0100, Jakub Jelinek wrote: > > On Tue, Mar 21, 2017 at 08:38:20AM +1000, Richard Henderson wrote: > > > On 03/21/2017 07:15 AM, Jakub Jelinek wrote: > > > > Not really sure what we should do if both i1 and i2 are frame related, > > > > shall > > > > we check for each of the CFA reg notes if they are available and equal? > > > > Or punt if either of the insns is frame related? > > > > > > I would punt if either is frame related. > > > > Ok, I'll test then the following patch and gather some statistic on how > > often we trigger this. > > The statistics I've gathered unfortunately shows that at least on > powerpc64le-linux it is very important to not give up if both i1 and i2 > are frame related and have rtx_equal_p notes. > I've set on unpatched old_insns_match_p flags when returning non-dir_none > and checked those flags in the various callers of these when about to > successfully perform cross-jumping, head-merging etc. > With /f vs. non-/f, the only 3 hits were on the new pr80102.C testcase > during powerpc64le-linux bootstrap/regtest, but /f vs. /f there were > 167601 hits.
Here is updated patch which allows cross-jumping of RTX_FRAME_RELATED_P insns, as long as they have the same CFA related notes on them (same order if more than one). Bootstrapped/regtested on powerpc64le-linux, ok for trunk? 2017-03-21 Jakub Jelinek <ja...@redhat.com> PR target/80102 * cfgcleanup.c (old_insns_match_p): Don't cross-jump in between /f and non-/f instructions. If both i1 and i2 are frame related, verify all CFA notes, their order and content. * g++.dg/opt/pr80102.C: New test. --- gcc/cfgcleanup.c.jj 2017-03-21 07:56:55.711233924 +0100 +++ gcc/cfgcleanup.c 2017-03-21 19:20:40.517746664 +0100 @@ -1149,6 +1149,11 @@ old_insns_match_p (int mode ATTRIBUTE_UN else if (p1 || p2) return dir_none; + /* Do not allow cross-jumping between frame related insns and other + insns. */ + if (RTX_FRAME_RELATED_P (i1) != RTX_FRAME_RELATED_P (i2)) + return dir_none; + p1 = PATTERN (i1); p2 = PATTERN (i2); @@ -1207,6 +1212,58 @@ old_insns_match_p (int mode ATTRIBUTE_UN } } + /* If both i1 and i2 are frame related, verify all the CFA notes + in the same order and with the same content. */ + if (RTX_FRAME_RELATED_P (i1)) + { + static enum reg_note cfa_note_kinds[] = { + REG_FRAME_RELATED_EXPR, REG_CFA_DEF_CFA, REG_CFA_ADJUST_CFA, + REG_CFA_OFFSET, REG_CFA_REGISTER, REG_CFA_EXPRESSION, + REG_CFA_VAL_EXPRESSION, REG_CFA_RESTORE, REG_CFA_SET_VDRAP, + REG_CFA_TOGGLE_RA_MANGLE, REG_CFA_WINDOW_SAVE, REG_CFA_FLUSH_QUEUE + }; + rtx n1 = REG_NOTES (i1); + rtx n2 = REG_NOTES (i2); + unsigned int i; + do + { + /* Skip over reg notes not related to CFI information. */ + while (n1) + { + for (i = 0; i < ARRAY_SIZE (cfa_note_kinds); i++) + if (REG_NOTE_KIND (n1) == cfa_note_kinds[i]) + break; + if (i != ARRAY_SIZE (cfa_note_kinds)) + break; + n1 = XEXP (n1, 1); + } + while (n2) + { + for (i = 0; i < ARRAY_SIZE (cfa_note_kinds); i++) + if (REG_NOTE_KIND (n2) == cfa_note_kinds[i]) + break; + if (i != ARRAY_SIZE (cfa_note_kinds)) + break; + n2 = XEXP (n2, 1); + } + if (n1 == NULL_RTX && n2 == NULL_RTX) + break; + if (n1 == NULL_RTX || n2 == NULL_RTX) + return dir_none; + if (XEXP (n1, 0) == XEXP (n2, 0)) + ; + else if (XEXP (n1, 0) == NULL_RTX || XEXP (n2, 0) == NULL_RTX) + return dir_none; + else if (!(reload_completed + ? rtx_renumbered_equal_p (XEXP (n1, 0), XEXP (n2, 0)) + : rtx_equal_p (XEXP (n1, 0), XEXP (n2, 0)))) + return dir_none; + n1 = XEXP (n1, 1); + n2 = XEXP (n2, 1); + } + while (1); + } + #ifdef STACK_REGS /* If cross_jump_death_matters is not 0, the insn's mode indicates whether or not the insn contains any stack-like --- gcc/testsuite/g++.dg/opt/pr80102.C.jj 2017-03-21 18:56:30.256698365 +0100 +++ gcc/testsuite/g++.dg/opt/pr80102.C 2017-03-21 18:56:30.256698365 +0100 @@ -0,0 +1,14 @@ +// PR target/80102 +// { dg-do compile } +// { dg-options "-fnon-call-exceptions -Os" } +// { dg-additional-options "-mminimal-toc" { target { powerpc*-*-* && lp64 } } } + +struct B { float a; B (float c) { for (int g; g < c;) ++a; } }; +struct D { D (B); }; + +int +main () +{ + B (1.0); + D e (0.0), f (1.0); +} Jakub