On Fri, Apr 16, 2021 at 12:02 PM Richard Sandiford via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> This patch fixes a regression introduced by the rtl-ssa patches.
> It was seen on HPPA but it might be latent elsewhere.
>
> The problem is that the traditional way of expanding an untyped_call
> is to emit sequences like:
>
>    (call (mem (symbol_ref "foo")))
>    (set (reg pseudo1) (reg result1))
>    ...
>    (set (reg pseudon) (reg resultn))
>
> The ABI specifies that result1..resultn are clobbered by the call but
> nothing in the RTL indicates that result1..resultn are the results
> of the call.  Normally, using a clobbered value gives undefined results,
> but in this case the results are well-defined and matter for correctness.
>
> This seems like a niche case, so I think it would be better to mark
> it explicitly rather than try to detect it heuristically.
>
> Note that in expand_builtin_apply we already have an rtx_insn *,
> so it doesn't matter whether we call emit_call_insn or emit_insn.
> Calling emit_insn seems more natural now that the gen_* call
> has been split out.  It also matches later code in the function.
>
> Tested on aarch64-linux-gnu, arm-linux-gnueabihf, armeb-eabi and
> x86_64-linux-gnu.  OK to install?

OK.  Does DF handle this correctly?

I wonder why we cannot simply do sth like

(call_insn (set (parallel [ (reg:...) (reg:...) ] ) (mem (symbol_ref...)))

or so?  But I guess we'd have to alter all targets for this...

Thanks,
Richard.

> Richard
>
>
> gcc/
>         PR rtl-optimization/98689
>         * reg-notes.def (UNTYPED_CALL): New note.
>         * combine.c (distribute_notes): Handle it.
>         * emit-rtl.c (try_split): Likewise.
>         * rtlanal.c (rtx_properties::try_to_add_insn): Likewise.  Assume
>         that calls with the note implicitly set all return value registers.
>         * builtins.c (expand_builtin_apply): Add a REG_UNTYPED_CALL
>         to untyped_calls.
> ---
>  gcc/builtins.c    |  8 ++++++--
>  gcc/combine.c     |  1 +
>  gcc/emit-rtl.c    |  1 +
>  gcc/reg-notes.def | 15 +++++++++++++++
>  gcc/rtlanal.c     |  9 +++++++++
>  5 files changed, 32 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/builtins.c b/gcc/builtins.c
> index 196dda3fa5e..d30c4eb62fc 100644
> --- a/gcc/builtins.c
> +++ b/gcc/builtins.c
> @@ -2490,8 +2490,12 @@ expand_builtin_apply (rtx function, rtx arguments, rtx 
> argsize)
>    if (targetm.have_untyped_call ())
>      {
>        rtx mem = gen_rtx_MEM (FUNCTION_MODE, function);
> -      emit_call_insn (targetm.gen_untyped_call (mem, result,
> -                                               result_vector (1, result)));
> +      rtx_insn *seq = targetm.gen_untyped_call (mem, result,
> +                                               result_vector (1, result));
> +      for (rtx_insn *insn = seq; insn; insn = NEXT_INSN (insn))
> +       if (CALL_P (insn))
> +         add_reg_note (insn, REG_UNTYPED_CALL, NULL_RTX);
> +      emit_insn (seq);
>      }
>    else if (targetm.have_call_value ())
>      {
> diff --git a/gcc/combine.c b/gcc/combine.c
> index 6cb5b0ca102..9063a07bd00 100644
> --- a/gcc/combine.c
> +++ b/gcc/combine.c
> @@ -14337,6 +14337,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, 
> rtx_insn *i3, rtx_insn *i2,
>         case REG_SETJMP:
>         case REG_TM:
>         case REG_CALL_DECL:
> +       case REG_UNTYPED_CALL:
>         case REG_CALL_NOCF_CHECK:
>           /* These notes must remain with the call.  It should not be
>              possible for both I2 and I3 to be a call.  */
> diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
> index 1113c58c49e..07e908624a0 100644
> --- a/gcc/emit-rtl.c
> +++ b/gcc/emit-rtl.c
> @@ -3964,6 +3964,7 @@ try_split (rtx pat, rtx_insn *trial, int last)
>           break;
>
>         case REG_CALL_DECL:
> +       case REG_UNTYPED_CALL:
>           gcc_assert (call_insn != NULL_RTX);
>           add_reg_note (call_insn, REG_NOTE_KIND (note), XEXP (note, 0));
>           break;
> diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
> index d7f0bfdab0b..995052ebc28 100644
> --- a/gcc/reg-notes.def
> +++ b/gcc/reg-notes.def
> @@ -233,6 +233,21 @@ REG_NOTE (STACK_CHECK)
>     insn.  This note is a SYMBOL_REF.  */
>  REG_NOTE (CALL_DECL)
>
> +/* Indicates that the call is an untyped_call.  These calls are special
> +   in that they set all of the target ABI's return value registers to a
> +   defined value without explicitly saying so.  For example, a typical
> +   untyped_call sequence has the form:
> +
> +       (call (mem (symbol_ref "foo")))
> +       (set (reg pseudo1) (reg result1))
> +       ...
> +       (set (reg pseudon) (reg resultn))
> +
> +   The ABI specifies that result1..resultn are clobbered by the call,
> +   but the RTL does not indicate that result1..resultn are the results
> +   of the call.  */
> +REG_NOTE (UNTYPED_CALL)
> +
>  /* Indicate that a call should not be verified for control-flow consistency.
>     The target address of the call is assumed as a valid address and no check
>     to validate a branch to the target address is needed.  The call is marked
> diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
> index 170420a610b..67a49e65fd8 100644
> --- a/gcc/rtlanal.c
> +++ b/gcc/rtlanal.c
> @@ -2333,6 +2333,15 @@ rtx_properties::try_to_add_insn (const rtx_insn *insn, 
> bool include_notes)
>               *ref_iter++ = rtx_obj_reference (regno, flags,
>                                                reg_raw_mode[regno], 0);
>         }
> +      /* Untyped calls implicitly set all function value registers.
> +        Again, we add them first in case the main pattern contains
> +        a fixed-form clobber.  */
> +      if (find_reg_note (insn, REG_UNTYPED_CALL, NULL_RTX))
> +       for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
> +         if (targetm.calls.function_value_regno_p (regno)
> +             && ref_iter != ref_end)
> +           *ref_iter++ = rtx_obj_reference (regno, rtx_obj_flags::IS_WRITE,
> +                                            reg_raw_mode[regno], 0);
>        if (ref_iter != ref_end && !RTL_CONST_CALL_P (insn))
>         {
>           auto mem_flags = rtx_obj_flags::IS_READ;

Reply via email to