On Wed, 13 Sep 2017, Jakub Jelinek wrote:

> Hi!
> 
> The following testcase fails on powerpc64le with -fcompare-debug.
> The problem is that find_many_sub_basic_blocks is called during
> expansion on a basic block where originally two __atomic_fetch_add
> calls have some debug stmts in between.  The rs6000 backend expands
> those atomic calls into a loop that starts with a CODE_LABEL and
> ends with a JUMP_INSN, so find_many_sub_basic_blocks must
> end a basic block after the JUMP_INSN from the first call and
> start a new basic block at the start of the second call.
> If there are no DEBUG_INSNs in between, it creates just those 2
> basic blocks, which is correct, but it doesn't ignore DEBUG_INSNs when
> deciding what to do and thus when there are DEBUG_ISNSs in between
> the flow_transfer_insn (JUMP_INSN) and CODE_LABEL, it creates yet
> another basic block that has just the DEBUG_INSNs in it.  That means
> different cfg between -g and -g0 and more differences later on.
> 
> As I wrote in the PR, if we have 2 loops and some code in between
> at GIMPLE, and in that code in between DCE all the non-debug stmts and
> have only debug stmts in there, we consider it a forwarder block and delete
> it with all those debug stmts (it is one of the unfortunate cases where we
> drop them on the floor, but there isn't really much we can do with those
> without adding new extensions like conditional debug stmts or debug phis).
> 
> The following patch attempts to do the same thing on RTL during
> find_many_sub_basic_blocks, i.e. ignore debug stmts when deciding what to
> do, trying to preserve debug insns somewhere if that is easily possible
> (if there is say a conditional jump with a fallthrough into debug insns
> followed by some real insn (not a CODE_LABEL nor BARRIER), the debug
> insns can go at the start of the fallthrough bb that would be created
> anyway).  If we have an insn that must end a bb and another one that must
> start a bb (CODE_LABEL) and only debug insns in between, we remove them.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux (in these two cases
> I've also gathered statistics and no debug insns during the
> bootstraps/regtests were actually removed) and powerpc64le-linux (forgot to
> apply the statistics patch, so no details, but it surely triggers at least
> on the testcase).  Ok for trunk?

Ok.

Thanks,
Richard.

> 2017-09-13  Jakub Jelinek  <ja...@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.
> 
> --- gcc/cfgbuild.c.jj 2017-09-12 21:57:53.084514168 +0200
> +++ gcc/cfgbuild.c    2017-09-13 09:15:57.701521179 +0200
> @@ -442,9 +442,10 @@ find_bb_boundaries (basic_block bb)
>    rtx_insn *end = BB_END (bb), *x;
>    rtx_jump_table_data *table;
>    rtx_insn *flow_transfer_insn = NULL;
> +  rtx_insn *debug_insn = NULL;
>    edge fallthru = NULL;
>  
> -  if (insn == BB_END (bb))
> +  if (insn == end)
>      return;
>  
>    if (LABEL_P (insn))
> @@ -455,22 +456,43 @@ find_bb_boundaries (basic_block bb)
>      {
>        enum rtx_code code = GET_CODE (insn);
>  
> +      if (code == DEBUG_INSN)
> +     {
> +       if (flow_transfer_insn && !debug_insn)
> +         debug_insn = insn;
> +     }
>        /* In case we've previously seen an insn that effects a control
>        flow transfer, split the block.  */
> -      if ((flow_transfer_insn || code == CODE_LABEL)
> -       && inside_basic_block_p (insn))
> +      else if ((flow_transfer_insn || code == CODE_LABEL)
> +            && inside_basic_block_p (insn))
>       {
> -       fallthru = split_block (bb, PREV_INSN (insn));
> +       rtx_insn *prev = PREV_INSN (insn);
> +
> +       /* If the first non-debug inside_basic_block_p insn after a control
> +          flow transfer is not a label, split the block before the debug
> +          insn instead of before the non-debug insn, so that the debug
> +          insns are not lost.  */
> +       if (debug_insn && code != CODE_LABEL && code != BARRIER)
> +         prev = PREV_INSN (debug_insn);
> +       fallthru = split_block (bb, prev);
>         if (flow_transfer_insn)
>           {
>             BB_END (bb) = flow_transfer_insn;
>  
> +           rtx_insn *next;
>             /* Clean up the bb field for the insns between the blocks.  */
>             for (x = NEXT_INSN (flow_transfer_insn);
>                  x != BB_HEAD (fallthru->dest);
> -                x = NEXT_INSN (x))
> -             if (!BARRIER_P (x))
> -               set_block_for_insn (x, NULL);
> +                x = next)
> +             {
> +               next = NEXT_INSN (x);
> +               /* Debug insns should not be in between basic blocks,
> +                  drop them on the floor.  */
> +               if (DEBUG_INSN_P (x))
> +                 delete_insn (x);
> +               else if (!BARRIER_P (x))
> +                 set_block_for_insn (x, NULL);
> +             }
>           }
>  
>         bb = fallthru->dest;
> @@ -480,6 +502,7 @@ find_bb_boundaries (basic_block bb)
>         bb->frequency = 0;
>         bb->count = profile_count::uninitialized ();
>         flow_transfer_insn = NULL;
> +       debug_insn = NULL;
>         if (code == CODE_LABEL && LABEL_ALT_ENTRY_P (insn))
>           make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, 0);
>       }
> @@ -502,17 +525,23 @@ find_bb_boundaries (basic_block bb)
>    /* In case expander replaced normal insn by sequence terminating by
>       return and barrier, or possibly other sequence not behaving like
>       ordinary jump, we need to take care and move basic block boundary.  */
> -  if (flow_transfer_insn)
> +  if (flow_transfer_insn && flow_transfer_insn != end)
>      {
>        BB_END (bb) = flow_transfer_insn;
>  
>        /* Clean up the bb field for the insns that do not belong to BB.  */
> -      x = flow_transfer_insn;
> -      while (x != end)
> +      rtx_insn *next;
> +      for (x = NEXT_INSN (flow_transfer_insn); ; x = next)
>       {
> -       x = NEXT_INSN (x);
> -       if (!BARRIER_P (x))
> +       next = NEXT_INSN (x);
> +       /* Debug insns should not be in between basic blocks,
> +          drop them on the floor.  */
> +       if (DEBUG_INSN_P (x))
> +         delete_insn (x);
> +       else if (!BARRIER_P (x))
>           set_block_for_insn (x, NULL);
> +       if (x == end)
> +         break;
>       }
>      }
>  
> --- gcc/testsuite/g++.dg/cpp0x/pr81325.C.jj   2017-09-12 22:17:54.662002067 
> +0200
> +++ gcc/testsuite/g++.dg/cpp0x/pr81325.C      2017-09-13 09:21:44.536059474 
> +0200
> @@ -0,0 +1,84 @@
> +// PR target/81325
> +// { dg-do compile { target c++11 } }
> +// { dg-options "-O2 -fcompare-debug" }
> +
> +struct A { A(const char *, const int & = 0); };
> +template <typename> struct B;
> +template <typename> struct C {
> +  int _M_i;
> +  void m_fn1() { __atomic_fetch_add(&_M_i, 0, __ATOMIC_RELAXED); }
> +};
> +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);
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to