Hi Alan,

On Tue, Nov 13, 2018 at 11:23:43PM +1030, Alan Modra wrote:
> Finally, the point of the previous patches in this series, support for
> inline PLT calls, keyed off -fno-plt.  This emits code using new
> relocations that tie all insns in the sequence together, so that the
> linker can edit the sequence back to a direct call should the call
> target turn out to be local.  An example of ELFv2 code to call puts is
> as follows:
> 
>      .reloc .,R_PPC64_PLTSEQ,puts
>         std 2,24(1)
>      .reloc .,R_PPC64_PLT16_HA,puts
>         addis 12,2,0
>      .reloc .,R_PPC64_PLT16_LO_DS,puts
>         ld 12,0(12)
>      .reloc .,R_PPC64_PLTSEQ,puts
>         mtctr 12
>      .reloc .,R_PPC64_PLTCALL,puts
>         bctrl
>         ld 2,24(1)
> 
> "addis 12,2,puts@plt@ha" and "ld 12,puts@plt@l(12)" are also supported
> by the assembler.  gcc instead uses the explicit R_PPC64_PLT16_HA and
> R_PPC64_PLT16_LO_DS relocs because when the call is to __tls_get_addr
> an extra reloc is emitted at every place where one is shown above, to
> specify the __tls_get_addr arg.  The linker expects the extra reloc to
> come first.  .reloc enforces that ordering.
> 
> The patch also changes code emitted for longcalls if the assembler
> supports the new marker relocs, so that these too can be edited.  One
> side effect of longcalls using PLT16 relocs is that they can now be
> resolved lazily by ld.so.
> 
> I don't support lazy inline PLT calls for ELFv1, because ELFv1 would
> need barriers to reliably load both the function address and toc
> pointer from the PLT.  ELFv1 -fno-plt uses the longcall sequence
> instead, which isn't edited by GNU ld.

That all sounds great :-)  Has this been tested with older binutils, too?


>       * config.in (HAVE_AS_PLTSEQ): Add.
>       * config/rs6000/predicates.md (indirect_call_operand): New.
>       * config/rs6000/rs6000-protos.h (rs6000_pltseq_template),
>       (rs6000_sibcall_sysv): Declare.
>       * config/rs6000/rs6000.c (init_cumulative_args): Set cookie
>       CALL_LONG for -fno-plt.
>       (print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ.
>       (rs6000_indirect_call_template_1): Emit .reloc directives for
>       UNSPEC_PLTSEQ calls.
>       (rs6000_pltseq_template): New function.
>       (rs6000_longcall_ref): Add arg parameter.  Use PLT16 insns if
>       relocs supported by assembler.  Move SYMBOL_REF test to callers.
>       (rs6000_call_aix): Adjust rs6000_longcall_ref call.  Package
>       insns in UNSPEC_PLTSEQ, preserving original func_desc.
>       (rs6000_call_sysv): Likewise.
>       (rs6000_sibcall_sysv): New function.
>       * config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default.
>       * config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA,
>       UNSPEC_PLT16_LO): New.
>       (pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New.
>       (call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero
>       cookie in constraints.  Test explicitly for flags in length attr.
>       Handle unspec operand 1.
>       (call_value_indirect_nonlocal_sysv): Likewise.
>       (call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1.
>       (call_indirect_elfv2, call_value_indirect_elfv2): Likewise.
>       (sibcall, sibcall_value): Use rs6000_sibcall_sysv.
>       (sibcall_indirect_nonlocal_sysv): New pattern.
>       (sibcall_value_indirect_nonlocal_sysv): Likewise.
>       (sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect
>       call alternatives.
>       * configure.ac: Check for gas plt sequence marker support.
>       * configure: Regenerate.


> @@ -10727,10 +10727,20 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree 
> fntype,
>      cum->nargs_prototype = n_named_args;
>  
>    /* Check for a longcall attribute.  */
> -  if ((!fntype && rs6000_default_long_calls)
> -      || (fntype
> -       && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
> -       && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
> +  if (((!fntype && rs6000_default_long_calls)
> +       || (fntype
> +        && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
> +        && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
> +      || (DEFAULT_ABI != ABI_DARWIN
> +       && !(fndecl
> +            && !DECL_EXTERNAL (fndecl)
> +            && !DECL_WEAK (fndecl)
> +            && (*targetm.binds_local_p) (fndecl))
> +       && (flag_plt
> +           ? (fntype
> +              && lookup_attribute ("noplt", TYPE_ATTRIBUTES (fntype)))
> +           : !(fntype
> +               && lookup_attribute ("plt", TYPE_ATTRIBUTES (fntype))))))
>      cum->call_cookie |= CALL_LONG;

Could you split this into a few cases?  Maybe with some extra locals.  It
is hard to understand the code as it is.

I mean like

  if (...)
    cum->call_cookie |= CALL_LONG;
  if (...)
    cum->call_cookie |= CALL_LONG;
  if (...)
    cum->call_cookie |= CALL_LONG;


> +(define_insn "*sibcall_indirect_nonlocal_sysv<mode>"

> +   (set (attr "length")
> +     (cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
> +                      (match_test "which_alternative != 1"))
> +                 (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | 
> CALL_V4_CLEAR_FP_ARGS))"))
> +               (const_string "12")
> +            (ior (and (match_test "!rs6000_speculate_indirect_jumps")
> +                      (match_test "which_alternative != 1"))
> +                (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | 
> CALL_V4_CLEAR_FP_ARGS))"))
> +               (const_string "8")]
> +           (const_string "4")))])

Please use set_attr_alternative for these.


Looks fine modulo those nits.  Okay for trunk.  Thanks!


Segher

Reply via email to