On Thu, Jul 14, 2022 at 10:12 PM Alexander Monakov <amona...@ispras.ru> wrote:
>
>
> On Thu, 14 Jul 2022, Richard Biener wrote:
>
> > Indeed.  Guess that's what __builtin_setjmp[_receiver] for SJLJ_EH got 
> > "right".
> >
> > When copying a block we do not copy labels so any "jumps" remain to the 
> > original
> > block and thus we are indeed able to isolate normal control flow.  Given 
> > that
> > returns_twice functions _do_ seem to be special, and also special as to how
> > we handle other abnormal receivers in duplicate_block.
>
> We do? Sorry, I don't see what you mean here, can you point me to specific 
> lines?

I'm referring to

      stmt = gsi_stmt (gsi);
      if (gimple_code (stmt) == GIMPLE_LABEL)
        continue;

but indeed, looking again we do _not_ skip a __builtin_setjmp_receiver
(but I don't
exactly remember the CFG setup with SJLJ EH and setjmp_{receiver,setup}.

> > So it might indeed make sense to special-case them in can_duplicate_block_p
> > ... (sorry for going back-and-forth ...)
> >
> > Note that I think this detail of duplicate_block (the function) and the hook
> > needs to be better documented (the semantics on incoming edges, not 
> > duplicating
> > labels used for incoming control flow).
> >
> > Can you see as to how to adjust the RTL side for this?  It looks like at 
> > least
> > some places set a REG_SETJMP note on call_insns (emit_call_1), I wonder
> > if in rtl_verify_flow_info[_1] (or its callees) we can check that such
> > calls come
> > first ... they might not since IIRC we do _not_ preserve abnormal edges when
> > expanding RTL (there's some existing bug about this and how this breaks some
> > setjmp tests) (but we try to recompute them?).
>
> No, we emit arguments/return value handling before/after a REG_SETJMP call,
> and yeah, we don't always properly recompute abnormal edges, so improving
> RTL in this respect seems hopeless.

:/  (but yes, nobody got to fixing PR57067 in the last 10 years)

> For example, it is easy enough to create
> a testcase where bb-reordering duplicates a returns_twice call, although it
> runs so late that perhaps later passes don't care:
>
> // gcc -O2 --param=max-grow-copy-bb-insns=100
> __attribute__((returns_twice))
> int rtwice(int);
> int g1(int), g2(int);
> void f(int i)
> {
>   do {
>     i = i%2 ? g1(i) : g2(i);
>   } while (i = rtwice(i));
> }
>
> FWIW, I also investigated https://gcc.gnu.org/PR101347
>
> > Sorry about the back-and-forth again ... your original patch looks OK for 
> > the
> > GIMPLE side but can you amend the cfghooks.{cc,h} documentation to
> > summarize our findings and
> > the desired semantics of duplicate_block in this respect?
>
> Like below?

Yes.

Thanks and sorry for the back and forth - this _is_ a mightly
complicated area ...

Richard.

> ---8<---
>
> Subject: [PATCH v3] tree-cfg: do not duplicate returns_twice calls
>
> A returns_twice call may have associated abnormal edges that correspond
> to the "second return" from the call. If the call is duplicated, the
> copies of those edges also need to be abnormal, but e.g. tracer does not
> enforce that. Just prohibit the (unlikely to be useful) duplication.
>
> gcc/ChangeLog:
>
>         * cfghooks.cc (duplicate_block): Expand comment.
>         * tree-cfg.cc (gimple_can_duplicate_bb_p): Reject blocks with
>         calls that may return twice.
> ---
>  gcc/cfghooks.cc | 13 ++++++++++---
>  gcc/tree-cfg.cc |  7 +++++--
>  2 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/gcc/cfghooks.cc b/gcc/cfghooks.cc
> index e435891fa..c6ac9532c 100644
> --- a/gcc/cfghooks.cc
> +++ b/gcc/cfghooks.cc
> @@ -1086,9 +1086,16 @@ can_duplicate_block_p (const_basic_block bb)
>    return cfg_hooks->can_duplicate_block_p (bb);
>  }
>
> -/* Duplicates basic block BB and redirects edge E to it.  Returns the
> -   new basic block.  The new basic block is placed after the basic block
> -   AFTER.  */
> +/* Duplicate basic block BB, place it after AFTER (if non-null) and redirect
> +   edge E to it (if non-null).  Return the new basic block.
> +
> +   If BB contains a returns_twice call, the caller is responsible for 
> recreating
> +   incoming abnormal edges corresponding to the "second return" for the copy.
> +   gimple_can_duplicate_bb_p rejects such blocks, while RTL likes to live
> +   dangerously.
> +
> +   If BB has incoming abnormal edges for some other reason, their 
> destinations
> +   should be tied to label(s) of the original BB and not the copy.  */
>
>  basic_block
>  duplicate_block (basic_block bb, edge e, basic_block after, copy_bb_data *id)
> diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
> index f846dc2d8..5bcf78198 100644
> --- a/gcc/tree-cfg.cc
> +++ b/gcc/tree-cfg.cc
> @@ -6346,12 +6346,15 @@ gimple_can_duplicate_bb_p (const_basic_block bb)
>      {
>        gimple *g = gsi_stmt (gsi);
>
> -      /* An IFN_GOMP_SIMT_ENTER_ALLOC/IFN_GOMP_SIMT_EXIT call must be
> +      /* Prohibit duplication of returns_twice calls, otherwise associated
> +        abnormal edges also need to be duplicated properly.
> +        An IFN_GOMP_SIMT_ENTER_ALLOC/IFN_GOMP_SIMT_EXIT call must be
>          duplicated as part of its group, or not at all.
>          The IFN_GOMP_SIMT_VOTE_ANY and IFN_GOMP_SIMT_XCHG_* are part of such 
> a
>          group, so the same holds there.  */
>        if (is_gimple_call (g)
> -         && (gimple_call_internal_p (g, IFN_GOMP_SIMT_ENTER_ALLOC)
> +         && (gimple_call_flags (g) & ECF_RETURNS_TWICE
> +             || gimple_call_internal_p (g, IFN_GOMP_SIMT_ENTER_ALLOC)
>               || gimple_call_internal_p (g, IFN_GOMP_SIMT_EXIT)
>               || gimple_call_internal_p (g, IFN_GOMP_SIMT_VOTE_ANY)
>               || gimple_call_internal_p (g, IFN_GOMP_SIMT_XCHG_BFLY)
> --
> 2.35.1
>

Reply via email to