On 2023/3/2 16:41, Richard Biener wrote:
On Thu, Mar 2, 2023 at 3:31 AM Xionghu Luo via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:

When spliting edge with self loop, the split edge should be placed just next to
the edge_in->src, otherwise it may generate different position latch bbs for
two consecutive self loops.  For details, please refer to:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93680#c4

Regression tested pass on x86_64-linux-gnu and aarch64-linux-gnu, OK for
master?

gcc/ChangeLog:

         PR gcov/93680
         * tree-cfg.cc (split_edge_bb_loc): Return edge_in->src for self loop.

gcc/testsuite/ChangeLog:

         PR gcov/93680
         * gcc.misc-tests/gcov-pr93680.c: New test.

Signed-off-by: Xionghu Luo <xionghu...@tencent.com>
---
  gcc/testsuite/gcc.misc-tests/gcov-pr93680.c | 24 +++++++++++++++++++++
  gcc/tree-cfg.cc                             |  2 +-
  2 files changed, 25 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-pr93680.c

diff --git a/gcc/testsuite/gcc.misc-tests/gcov-pr93680.c 
b/gcc/testsuite/gcc.misc-tests/gcov-pr93680.c
new file mode 100644
index 00000000000..b2bf9e626fc
--- /dev/null
+++ b/gcc/testsuite/gcc.misc-tests/gcov-pr93680.c
@@ -0,0 +1,24 @@
+/* { dg-options "-fprofile-arcs -ftest-coverage" } */
+/* { dg-do run { target native } } */
+
+int f(int s, int n)
+{
+  int p = 0;
+
+  switch (s)
+  {
+    case 0: /* count(5) */
+      do { p++; } while (--n); /* count(5) */
+      return p; /* count(1) */
+
+    case 1: /* count(5) */
+      do { p++; } while (--n); /* count(5) */
+      return p; /* count(1) */
+  }
+
+  return 0;
+}
+
+int main() { f(0, 5); f(1, 5); return 0; }
+
+/* { dg-final { run-gcov gcov-pr93680.c } } */
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index a9fcc7fd050..6fa1d83d366 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -3009,7 +3009,7 @@ split_edge_bb_loc (edge edge_in)
    if (dest_prev)
      {
        edge e = find_edge (dest_prev, dest);
-      if (e && !(e->flags & EDGE_COMPLEX))
+      if ((e && !(e->flags & EDGE_COMPLEX)) || edge_in->src == edge_in->dest)

I think this should eventually apply to all backedge edge_in, correct?
  But of course
we cannot easily test for this here.

Still since this affects ordering in the {next,prev}_bb chain only but not CFG
semantics I wonder how it can affect coverage?  Isn't it only by chance that
this block order survives?

For case:

1 int f(int s, int n)
2 {
3  int p = 0;
4  int q = 0;
5
6  switch (s)
7    {
8    case 0:
9      do { p++; } while (--n);
10      return p;
11
12    case 1:
13      do { p++; } while (--n);
14      return p;
15    }
16
17  return 0;
18 }
19
20 int main() { f(0, 5); f(1, 5);}


current GCC generates:

<bb 2> :
...

 <bb 3> :                <= first loop
...
    goto <bb 4>; [INV]
  else
    goto <bb 5>; [INV]

  <bb 4> :               <= first latch bb
  goto <bb 3>; [100.00%]

  <bb 5> :
...
  goto <bb 10>; [INV]

  <bb 6> :               <= second latch bb

  <bb 7> :                <= second loop
...
    goto <bb 6>; [INV]
  else
    goto <bb 8>; [INV]


<bb 4> and <bb 6> are created by split_edge->split_edge_bb_loc, <bb 4>
is located after the loop, but <bb 6> is located before the loop.

First call of split_edge_bb_loc, the dest_prev is <bb 2>, and find_edge
did find a edge from <bb 2> to <bb 3>, the returned afte_bb is <bb 3>, so
latch <bb 4> is put after the loop

but second call of split_edge_bb_loc, the dest_prev is <bb 5>, so find_edge
return 0, and the returned after_bb is <bb 5>, then the created latch <bb 6>
is put before the loop...

Different latch bb position caused different gcno, while gcov has poor
information and not that smart to recognize it:(, is it reasonable to keep
this kind of loops same order?


 small.gcno:  648:                  block 2:`small.c':1, 3, 4, 6
 small.gcno:  688:    01450000:  36:LINES
 small.gcno:  700:                  block 3:`small.c':8, 9
 small.gcno:  732:    01450000:  32:LINES
 small.gcno:  744:                  block 5:`small.c':10
-small.gcno:  772:    01450000:  32:LINES
-small.gcno:  784:                  block 6:`small.c':12
-small.gcno:  812:    01450000:  36:LINES
-small.gcno:  824:                  block 7:`small.c':12, 13
+small.gcno:  772:    01450000:  36:LINES
+small.gcno:  784:                  block 6:`small.c':12, 13
+small.gcno:  816:    01450000:  32:LINES
+small.gcno:  828:                  block 8:`small.c':14
 small.gcno:  856:    01450000:  32:LINES
-small.gcno:  868:                  block 8:`small.c':14
-small.gcno:  896:    01450000:  32:LINES
-small.gcno:  908:                  block 9:`small.c':17
+small.gcno:  868:                  block 9:`small.c':17




For the case when both edge_in->src has more than one successor and
edge_in->dest has more than one predecessor there isn't any good heuristic
to make printing the blocks in chain order "nice" (well, the backedge
one maybe).

But as said - this order shouldn't have any effect on semantics ...

         return edge_in->src;
      }
    return dest_prev;
--
2.27.0

Reply via email to