trippels@gcc2-power8 llvm_build % cat test.ii struct A { A(char *, const int & = 0); }; template <typename> struct B; template <typename> struct C { int _M_i; void m_fn1() { __atomic_fetch_add(&_M_i, 0, 0); } }; struct D { int *Data; long Length = 0; D(int) : Data() {} }; template <> struct B<int> : C<int> {}; struct F { B<int> RefCount; void m_fn2() { RefCount.m_fn1(); } }; struct G { F *Obj; G(const G &p1) : Obj(p1.Obj) { if (Obj) { F *a = 0; a->m_fn2(); } } }; struct H { int CPlusPlus : 1; }; struct I { enum {} KindId; }; template <typename ResultT, typename ArgT> struct J { void operator()(); ResultT operator()(ArgT) {} }; struct K { int AllowBind; I SupportedKind; I RestrictKind; G Implementation; }; struct L { L(int) : Implementation(Implementation) {} K Implementation; }; struct M { int Param1; }; struct N { N(int, L &p2) : Param2(p2) {} L Param2; }; struct O { L m_fn3(); }; L ignoringImpCasts(L); J<O, L> b; L hasName(const A &); M hasOverloadedOperatorName(D); J<O, int> c; struct P { void m_fn4(L, int); }; struct Q { void m_fn5(P *); }; H d; void Q::m_fn5(P *p1) { if (!d.CPlusPlus) { c(); L e = 0, f = ignoringImpCasts(e); b(ignoringImpCasts(f)).m_fn3(); } hasOverloadedOperatorName(0); hasName(""); L g = 0; N(0, g); L h(0); p1->m_fn4(h, 0); } trippels@gcc2-power8 llvm_build % g++ --save-temps -c -O2 -fcompare-debug test.ii test.ii: In member function ‘void Q::m_fn5(P*)’: test.ii:77:13: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings] hasName(""); ^ g++: error: test.ii: -fcompare-debug failure trippels@gcc2-power8 llvm_build % diff -u test.gkd test.gk.gkd --- test.gkd 2017-07-05 13:49:05.946937825 +0000 +++ test.gk.gkd 2017-07-05 13:49:06.076940789 +0000 @@ -131,7 +131,7 @@ (int_list:REG_BR_PROB 3300 (nil))) -> 30) (note # 0 0 [bb 3] NOTE_INSN_BASIC_BLOCK) -(insn:TI # 0 0 (set (reg/f:DI 31 31 [205]) +(insn:TI # 0 0 (set (reg/f:DI 31 31 [206]) (plus:DI (reg/f:DI 1 1) (const_int 32 [0x20])))# {*adddi3} (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) @@ -143,7 +143,7 @@ (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) (const_int 56 [0x38])) (nil))) -(insn # 0 0 (set (reg/f:DI 30 30 [206]) +(insn # 0 0 (set (reg/f:DI 30 30 [205]) (plus:DI (reg/f:DI 1 1) (const_int 80 [0x50])))# {*adddi3} (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) @@ -198,7 +198,7 @@ (expr_list:REG_EQUAL (symbol_ref/f:DI ("*.LC0") [flags 0x82] <var_decl # *.LC0>) (nil))) (insn # 0 0 (set (reg:DI 3 3) - (reg/f:DI 30 30 [206])) "test.ii":77# {*movdi_internal64} + (reg/f:DI 30 30 [205])) "test.ii":77# {*movdi_internal64} (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) (const_int 80 [0x50])) (nil))) @@ -223,13 +223,13 @@ (expr_list:DI (use (reg:DI 5 5)) (nil)))))) (insn # 0 0 (set (reg:DI 4 4) - (reg/f:DI 30 30 [206])) "test.ii":77# {*movdi_internal64} - (expr_list:REG_DEAD (reg/f:DI 30 30 [206]) + (reg/f:DI 30 30 [205])) "test.ii":77# {*movdi_internal64} + (expr_list:REG_DEAD (reg/f:DI 30 30 [205]) (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) (const_int 80 [0x50])) (nil)))) (insn # 0 0 (set (reg:DI 3 3) - (reg/f:DI 31 31 [205])) "test.ii":77# {*movdi_internal64} + (reg/f:DI 31 31 [206])) "test.ii":77# {*movdi_internal64} (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) (const_int 32 [0x20])) (nil))) @@ -267,8 +267,8 @@ (expr_list:REG_EQUIV (const_int 0 [0]) (nil))) (insn # 0 0 (set (reg:DI 4 4) - (reg/f:DI 31 31 [205])) "test.ii":81# {*movdi_internal64} - (expr_list:REG_DEAD (reg/f:DI 31 31 [205]) + (reg/f:DI 31 31 [206])) "test.ii":81# {*movdi_internal64} + (expr_list:REG_DEAD (reg/f:DI 31 31 [206]) (expr_list:REG_EQUAL (plus:DI (reg/f:DI 111 sfp) (const_int 32 [0x20])) (nil)))) @@ -369,7 +369,7 @@ (expr_list:REG_EQUAL (const:DI (plus:DI (symbol_ref:DI ("*.LANCHOR0") [flags 0x182]) (const_int 4 [0x4]))) (nil))) -(insn # 0 0 (set (reg/f:DI 31 31 [205]) +(insn # 0 0 (set (reg/f:DI 31 31 [206]) It looks like an ancient issue, because even it fails even with gcc-4.8.5.
Unfortunately confirmed, caused by (probably) in RTL expansion: try_optimize_cfg iteration 1 Merging block 3 into block 2... Merged blocks 2 and 3. Merged 2 and 3 without moving. Forwarding edge 17->18 to 19 failed. Where w/o -g there's no forwarding failure. The CFG diverges here: <bb 9> [53.47%] [count: INV]: # DEBUG D#8 => &g # DEBUG D#9 => D#8 # DEBUG this => D#9 # DEBUG a => 0B # DEBUG this => 0B # DEBUG D#2 => &MEM[(struct F *)0B].RefCount.D.2982 # DEBUG this => D#2 _77 = &MEM[(struct C *)0B]._M_i; __atomic_fetch_add_4 (_77, 0, 0); # DEBUG this => NULL [some # DEBUG...] # DEBUG this => D#2 __atomic_fetch_add_4 (_77, 0, 0); # DEBUG this => NULL Because __atomic_fetch_add_4 is eventually expanded as: (code_label 93 92 436 8 5 (nil) [1 uses]) (note 436 93 94 8 [bb 8] NOTE_INSN_BASIC_BLOCK) (insn 94 436 95 8 (set (reg:SI 152) (unspec_volatile:SI [ (mem/v:SI (reg/f:DI 131 [ _76 ]) [-1 S4 A128]) ] UNSPECV_LL)) "/home/marxin/Programming/testcases/pr82325.cpp":7 -1 (nil)) (insn 95 94 96 8 (set (reg:SI 153) (plus:SI (reg:SI 152) (const_int 0 [0]))) "/home/marxin/Programming/testcases/pr82325.cpp":7 -1 (nil)) (insn 96 95 97 8 (parallel [ (set (reg:CC 154) (unspec_volatile:CC [ (const_int 0 [0]) ] UNSPECV_SC)) (set (mem/v:SI (reg/f:DI 131 [ _76 ]) [-1 S4 A128]) (reg:SI 153)) ]) "/home/marxin/Programming/testcases/pr82325.cpp":7 -1 (nil)) (jump_insn 97 96 437 8 (set (pc) (if_then_else (ne (reg:CC 154) (const_int 0 [0])) (label_ref 93) (pc))) "/home/marxin/Programming/testcases/pr82325.cpp":7 -1 (int_list:REG_BR_PROB 18 (nil)) -> 93) which is a loop. Due to that a different CFG is created. And the failure 'Forwarding edge 17->18 to 19 failed.' is attempt to skip from first atomic fetch loop to another. Fails due to existence of bunch of debug statements in between. Huh, still not sure where is error, can we have one __atomic_fetch_add_4 following another? GIMPLE representation does not represent fact that's a loop code. Advice welcomed.
I'll have a look.
I believe this is a bug in find_many_sub_basic_blocks. When looking at say: int i; int bar (void); void foo (int x) { l1: i += 2; if (bar ()) goto l1; int a = x + 5; int b = x + 10; l2: i += 2; if (bar ()) goto l2; } where before cddce1 we have at -O2 -g: ... goto <bb 5>; [INV] [count: INV] ... <bb 5> [0.00%] [count: INV]: a_13 = x_12(D) + 5; # DEBUG a => a_13 b_14 = x_12(D) + 10; # DEBUG b => b_14 <bb 6> [0.00%] [count: INV]: l2: and cddce1 decides to remove the unused a_13 and b_14, we just kill the forwarder block bb 5 and the debug stmts are dropped on the floor (which is unfortunate and on this testcase actually it wouldn't be impossible to move the debug stmts to the following block if the underlying vars are not mentioned in that loop and there are no debug stmts for that either, but we don't go that far). CCing Alex, because this is a nice example where debug stmts as well as frontier stmts are dropped on the floor. Anyway, I believe at least for now find_many_sub_basic_blocks should just throw away sequences of debug stmts in between an instruction that must end a basic block and instruction that must start a basic block.
Created attachment 42160 [details] gcc8-pr81325.patch Untested fix.
Author: jakub Date: Thu Sep 14 08:07:30 2017 New Revision: 252752 URL: https://gcc.gnu.org/viewcvs?rev=252752&root=gcc&view=rev Log: PR target/81325 * cfgbuild.c (find_bb_boundaries): Ignore debug insns in decisions if and where to split a bb, except for splitting before debug insn sequences followed by non-label real insn. Delete debug insns in between basic blocks. * g++.dg/cpp0x/pr81325.C: New test. Added: trunk/gcc/testsuite/g++.dg/cpp0x/pr81325.C Modified: trunk/gcc/ChangeLog trunk/gcc/cfgbuild.c trunk/gcc/testsuite/ChangeLog
Author: jakub Date: Fri Sep 15 11:26:03 2017 New Revision: 252805 URL: https://gcc.gnu.org/viewcvs?rev=252805&root=gcc&view=rev Log: Backported from mainline 2017-09-14 Jakub Jelinek <jakub@redhat.com> PR target/81325 * cfgbuild.c (find_bb_boundaries): Ignore debug insns in decisions if and where to split a bb, except for splitting before debug insn sequences followed by non-label real insn. Delete debug insns in between basic blocks. * g++.dg/cpp0x/pr81325.C: New test. Added: branches/gcc-7-branch/gcc/testsuite/g++.dg/cpp0x/pr81325.C Modified: branches/gcc-7-branch/gcc/ChangeLog branches/gcc-7-branch/gcc/cfgbuild.c branches/gcc-7-branch/gcc/testsuite/ChangeLog
Fixed for 7.3+. Tried to backport this to 6.x, but the testcase fails with -fcompare-debug failure even with the patch.
Closing.