Bug 81325 - -fcompare-debug failure on ppc64le
Summary: -fcompare-debug failure on ppc64le
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Jakub Jelinek
URL:
Keywords: compare-debug-failure
Depends on:
Blocks:
 
Reported: 2017-07-05 13:52 UTC by Markus Trippelsdorf
Modified: 2022-01-18 23:30 UTC (History)
4 users (show)

See Also:
Host:
Target: ppc64le
Build:
Known to work:
Known to fail: 4.8.5, 4.9.3, 5.3.0, 6.4.0, 7.1.0, 8.0
Last reconfirmed: 2017-09-11 00:00:00


Attachments
gcc8-pr81325.patch (2.15 KB, patch)
2017-09-12 16:33 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Trippelsdorf 2017-07-05 13:52:20 UTC
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.
Comment 1 Martin Liška 2017-09-11 13:44:32 UTC
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.
Comment 2 Jakub Jelinek 2017-09-11 14:49:17 UTC
I'll have a look.
Comment 3 Jakub Jelinek 2017-09-12 11:44:12 UTC
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.
Comment 4 Jakub Jelinek 2017-09-12 16:33:12 UTC
Created attachment 42160 [details]
gcc8-pr81325.patch

Untested fix.
Comment 5 Jakub Jelinek 2017-09-14 08:08:01 UTC
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
Comment 6 Jakub Jelinek 2017-09-15 11:26:34 UTC
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
Comment 7 Jakub Jelinek 2017-09-16 12:56:16 UTC
Fixed for 7.3+.  Tried to backport this to 6.x, but the testcase fails with -fcompare-debug failure even with the patch.
Comment 8 Markus Trippelsdorf 2017-11-21 05:54:33 UTC
Closing.